1. ホーム
  2. javascript

[解決済み] javascript/ブラウザでjquery ajaxのレスポンスをキャッシュする

2022-02-10 16:15:21

質問内容

javascript/ブラウザで、ajaxレスポンスのキャッシュを有効にしたいのですが、どうすればよいですか?

からの jquery.ajax docs :

デフォルトでは、リクエストは常に発行されますが、ブラウザが提供するのは の結果をキャッシュから取り出すことができます。キャッシュされた結果を使用しないようにするには キャッシュを false に設定します。アセットがある場合、リクエストの失敗を報告させるために が最後のリクエスト以降に変更されていない場合は、 ifModified を true に設定します。

しかし、どちらも強制的なキャッシュには対応していません。

動機は? を置きたい。 $.ajax({...}) の呼び出しは、初期化関数の中にあり、そのうちのいくつかは同じURLをリクエストします。これらの初期化関数を1つだけ呼び出す必要がある場合もあれば、複数呼び出す場合もあります。

そこで、特定のURLがすでに読み込まれている場合、サーバーへのリクエストを最小限に抑えたいのです。

私は自分自身のソリューションをロールバックすることができましたが(少し難しい!)、私はこれを行うための標準的な方法があるかどうかを知りたいです。

どのように解決するのですか?

cache:true はGETとHEADリクエストでのみ動作します。

あなたが言ったように、これらの線に沿った何かで独自のソリューションをロールバックすることができます。

var localCache = {
    data: {},
    remove: function (url) {
        delete localCache.data[url];
    },
    exist: function (url) {
        return localCache.data.hasOwnProperty(url) && localCache.data[url] !== null;
    },
    get: function (url) {
        console.log('Getting in cache for url' + url);
        return localCache.data[url];
    },
    set: function (url, cachedData, callback) {
        localCache.remove(url);
        localCache.data[url] = cachedData;
        if ($.isFunction(callback)) callback(cachedData);
    }
};

$(function () {
    var url = '/echo/jsonp/';
    $('#ajaxButton').click(function (e) {
        $.ajax({
            url: url,
            data: {
                test: 'value'
            },
            cache: true,
            beforeSend: function () {
                if (localCache.exist(url)) {
                    doSomething(localCache.get(url));
                    return false;
                }
                return true;
            },
            complete: function (jqXHR, textStatus) {
                localCache.set(url, jqXHR, doSomething);
            }
        });
    });
});

function doSomething(data) {
    console.log(data);
}

作業用フィドルはこちら

EDIT: この投稿が人気になったので、タイムアウトキャッシュを管理したい人のために、さらに良い答えがあります。 $.ajax() を使っているので $.ajaxPrefilter() . あとは {cache: true} で、キャッシュを正しく処理することができます。

var localCache = {
    /**
     * timeout for cache in millis
     * @type {number}
     */
    timeout: 30000,
    /** 
     * @type {{_: number, data: {}}}
     **/
    data: {},
    remove: function (url) {
        delete localCache.data[url];
    },
    exist: function (url) {
        return !!localCache.data[url] && ((new Date().getTime() - localCache.data[url]._) < localCache.timeout);
    },
    get: function (url) {
        console.log('Getting in cache for url' + url);
        return localCache.data[url].data;
    },
    set: function (url, cachedData, callback) {
        localCache.remove(url);
        localCache.data[url] = {
            _: new Date().getTime(),
            data: cachedData
        };
        if ($.isFunction(callback)) callback(cachedData);
    }
};

$.ajaxPrefilter(function (options, originalOptions, jqXHR) {
    if (options.cache) {
        var complete = originalOptions.complete || $.noop,
            url = originalOptions.url;
        //remove jQuery cache as we have our own localCache
        options.cache = false;
        options.beforeSend = function () {
            if (localCache.exist(url)) {
                complete(localCache.get(url));
                return false;
            }
            return true;
        };
        options.complete = function (data, textStatus) {
            localCache.set(url, data, complete);
        };
    }
});

$(function () {
    var url = '/echo/jsonp/';
    $('#ajaxButton').click(function (e) {
        $.ajax({
            url: url,
            data: {
                test: 'value'
            },
            cache: true,
            complete: doSomething
        });
    });
});

function doSomething(data) {
    console.log(data);
}

そして、このフィドルは CAREFUL, $.Deferredで動作しない。

ここでは、deferred で動作する、しかし欠陥のある実装を紹介します。

var localCache = {
    /**
     * timeout for cache in millis
     * @type {number}
     */
    timeout: 30000,
    /** 
     * @type {{_: number, data: {}}}
     **/
    data: {},
    remove: function (url) {
        delete localCache.data[url];
    },
    exist: function (url) {
        return !!localCache.data[url] && ((new Date().getTime() - localCache.data[url]._) < localCache.timeout);
    },
    get: function (url) {
        console.log('Getting in cache for url' + url);
        return localCache.data[url].data;
    },
    set: function (url, cachedData, callback) {
        localCache.remove(url);
        localCache.data[url] = {
            _: new Date().getTime(),
            data: cachedData
        };
        if ($.isFunction(callback)) callback(cachedData);
    }
};

$.ajaxPrefilter(function (options, originalOptions, jqXHR) {
    if (options.cache) {
        //Here is our identifier for the cache. Maybe have a better, safer ID (it depends on the object string representation here) ?
        // on $.ajax call we could also set an ID in originalOptions
        var id = originalOptions.url+ JSON.stringify(originalOptions.data);
        options.cache = false;
        options.beforeSend = function () {
            if (!localCache.exist(id)) {
                jqXHR.promise().done(function (data, textStatus) {
                    localCache.set(id, data);
                });
            }
            return true;
        };

    }
});

$.ajaxTransport("+*", function (options, originalOptions, jqXHR, headers, completeCallback) {

    //same here, careful because options.url has already been through jQuery processing
    var id = originalOptions.url+ JSON.stringify(originalOptions.data);

    options.cache = false;

    if (localCache.exist(id)) {
        return {
            send: function (headers, completeCallback) {
                completeCallback(200, "OK", localCache.get(id));
            },
            abort: function () {
                /* abort code, nothing needed here I guess... */
            }
        };
    }
});

$(function () {
    var url = '/echo/jsonp/';
    $('#ajaxButton').click(function (e) {
        $.ajax({
            url: url,
            data: {
                test: 'value'
            },
            cache: true
        }).done(function (data, status, jq) {
            console.debug({
                data: data,
                status: status,
                jqXHR: jq
            });
        });
    });
});

フィドルHERE キャッシュIDがjson2 libのJSONオブジェクト表現に依存している問題があります。

コンソール表示(F12)またはFireBugを使用して、キャッシュによって生成されたいくつかのログを表示します。