JavaScriptでXMLHttpRequestの結果をキャッシュするの何度も書いてるけどまた書いてしまった.
去年の11月くらいに書いたのこんな感じ.responseTextをハッシュに入れるみたいな感じ.エラー出たらメッセージ出してあきらめるというのはアプリケーション固有のエラー処理だから,ここでやるのは変だと思う.
_ajaxCache: {} _ajax: (url, callback) -> self = this if self._ajaxCache[url] callback self._ajaxCache[url] return $.ajax type: 'GET' url: url success: (res) -> self._ajaxCache[url] = res callback res error: -> alert('通信時にエラーが発生しました.時間をおいて試してみてください.') return
今年の5月にlocalStorageに保存するの書いてた.POSTする機能もついてる.jQuery Deferredを使ってるからエラーも返せる.localStorageに保存するから一度受信したらページをリロードしても一瞬で返ってくる.GETするリソースの内容が変わるときには使えない.IE7では使えない.
DataStorage = save: (data) -> dfd = $.Deferred() $.ajax url: '/data/' data: data: data type: 'POST' dataType: 'text' success: (key) -> localStorage["data-#{key}"] = data dfd.resolve key error: -> dfd.reject() dfd.promise() get: (key) -> dfd = $.Deferred() dataKey = "data-#{key}" if localStorage[dataKey] dfd.resolve localStorage[dataKey] else $.ajax url: "/data/#{key}" type: 'GET' dataType: 'text' success: (data) -> localStorage[dataKey] = data dfd.resolve data error: -> dfd.reject() dfd.promise() clearCache: -> localStorage.clear()
今年の7月に書いたやつ.仕事で書いたからコメント書いてある.リロードボタンでリロードする機能があったから,キャッシュを無効にするオプションが付いてるのと,thenでキャッシュを作ってるのがおしゃれ.
ajaxGetOrCache : function(url, force_disable_cache) { // jqXHRではなくDeferredオブジェクトが返ることがあるので使う側で注意すること var self = this; // forceじゃなくてキャッシュあったら返す if (!force_disable_cache && self.ajaxGetOrCacheCache[url]) { var dfd = $.Deferred(); dfd.resolve(self.ajaxGetOrCacheCache[url]); return dfd.promise(); } // thenを追加してキャッシュに保存するというのをやっています return $.ajax({ url: url }).then(function(res) { self.ajaxGetOrCacheCache[url] = res; }); }, ajaxGetOrCacheCache: {}
昨日書いたやつ.一箇所への通信が1つのオブジェクトになってるとよい気がしたから書いてみた.先にjQuery Deferedを返す関数を受け取ってインスタンスを作っておいて,結果が必要になったタイミングで実行する.jQuery Deferredのthenはresolveされていたら結果がすぐに返るから値をキャッシュするのに使える.
Later = function (f) { this.f = f; }; Later.prototype = { get : function(callback) { if (!this.deferred) { this.deferred = this.f(); } return this.deferred; } };
こうやって使う.
// ここではまだ通信しない var top_page = new Later(function() { return $.get('/'); }); // 必要になったときにget()すると通信する top_page.get().then(function(res) { console.log(res.length); }); // 次に呼んだときはすぐに結果が返る top_page.get().then(function(res) { console.log(res.length); });
さっきのでいい気がしてたけどget()すると関数を呼んでreturnしてるだけであまり仕事してない.オブジェクト作るまでもない.
今日書いたやつ.高階関数になってる.渡された関数を最初の一回だけ呼び,それ以降そのときの結果を返す.
once = function (f) { var result, called; return function() { if (!called) { result = f(); called = true; } return result; }; };
こうやって使う.
// ここではまだ通信しない var top_page = once(function() { return $.get('/'); }); // ここで通信する top_page().then(function(res) { console.log(res.length); }); // ここはすぐに結果が返る top_page().then(function(res) { console.log(res.length); });
最後のシンプルだし何にでも使える.最初の一回だけalertするとか.
var hi = once(function() { alert('hi'); }); // 1回だけalert出る hi(); hi();
通信結果のキャッシュしたかったのがいろいろやってるうちに汎用的なものができておもしろかった.
ここまで書いて気付いたけど最初のはURL管理してるけどあとのほうのは管理してない.アプリケーションの複数の場所から同一のURLにアクセスする場合があるときは最後のほうのもハッシュに入れたりする必要がある.シンプルになって喜んでたけど機能なくなってた.
追記
@hitode909 キャッシュの奴、高階関数版でもキャッシュ結果に名前紐付けとくようにしたら、URL管理も出来て便利そうですね
— 人さん (@r7kamura) 8月 25, 2012
@hitode909 こんな感じや / once.js — Gist gist.github.com/3463264
— 人さん (@r7kamura) 8月 25, 2012
@r7kamura よさそう,なんかmemoiseの変なやつっぽい
— 趣味はマリンスポーツですさん (@hitode909) 8月 25, 2012
@hitode909 別のところで同じ関数使い回したときにおかしくなりそうですね
— 人さん (@r7kamura) 8月 25, 2012
@r7kamura callback.toString()をキーにするというのを考えました gist.github.com/3463313
— 趣味はマリンスポーツですさん (@hitode909) 8月 25, 2012
@hitode909 toStringした意味を考えています
— 人さん (@r7kamura) 8月 25, 2012
@r7kamura toStringなくてよかったですね
— 趣味はマリンスポーツですさん (@hitode909) 8月 25, 2012