在 javascript/浏览器中缓存 jquery ajax 响应

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/17104265/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-26 18:26:32  来源:igfitidea点击:

Caching a jquery ajax response in javascript/browser

javascriptjqueryajaxcachingbrowser

提问by cammil

I would like to enable caching of an ajax response in javascript/browser.

我想在 javascript/浏览器中启用 ajax 响应的缓存。

From the jquery.ajax docs:

jquery.ajax 文档

By default, requests are always issued, but the browser may serve results out of its cache. To disallow use of the cached results, set cache to false. To cause the request to report failure if the asset has not been modified since the last request, set ifModified to true.

默认情况下,总是发出请求,但浏览器可能会从其缓存中提供结果。要禁止使用缓存结果,请将缓存设置为 false。如果资产自上次请求以来没有被修改,要使请求报告失败,请将 ifModified 设置为 true。

However, neither of these address forcing caching.

但是,这些地址都没有强制缓存。

Motivation:I want to put $.ajax({...})calls in my initialisation functions, some of which request the same url. Sometimes I need to call one of these initialisation functions, sometimes I call several.

动机:我想$.ajax({...})在我的初始化函数中调用,其中一些请求相同的 url。有时我需要调用这些初始化函数之一,有时我会调用几个。

So, I want to minimise the requests to the server if that particular url has already been loaded.

因此,如果该特定 url 已经加载,我想最小化对服务器的请求。

I could roll my own solution (with some difficulty!), but I would like to know if there is a standard way of doing this.

我可以推出自己的解决方案(有一些困难!),但我想知道是否有标准的方法来做到这一点。

回答by TecHunter

cache:trueonly works with GET and HEAD request.

cache:true仅适用于 GET 和 HEAD 请求。

You could roll your own solution as you said with something along these lines :

你可以像你所说的那样推出自己的解决方案:

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);
}

Working fiddle here

在这里工作小提琴

EDIT: as this post becomes popular, here is an even better answer for those who want to manage timeout cache and you also don't have to bother with all the mess in the $.ajax()as I use $.ajaxPrefilter(). Now just setting {cache: true}is enough to handle the cache correctly :

编辑:随着这篇文章变得流行,对于那些想要管理超时缓存的人来说,这里有一个更好的答案,而且你也不必因为我使用$.ajaxPrefilter()而烦恼$.ajax()中的所有混乱. 现在只需设置就足以正确处理缓存:{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);
}

And the fiddle hereCAREFUL, not working with $.Deferred

这里的小提琴小心,不使用 $.Deferred

Here is a working but flawed implementation working with 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
            });
        });
    });
});

Fiddle HERESome issues, our cache ID is dependent of the json2 lib JSON object representation.

Fiddle HERE有些问题,我们的缓存 ID 依赖于 json2 lib JSON 对象表示。

Use Console view (F12) or FireBug to view some logs generated by the cache.

使用控制台视图 (F12) 或 FireBug 查看缓存生成的一些日志。

回答by immayankmodi

I was looking for caching for my phonegap app storage and I found the answer of @TecHunter which is great but done using localCache.

我正在寻找我的 phonegap 应用程序存储的缓存,我找到了@TecHunter 的答案,它很棒但使用localCache.

I found and come to know that localStorage is another alternative to cache the data returned by ajax call. So, I created one demo using localStoragewhich will help others who may want to use localStorageinstead of localCachefor caching.

我发现并知道 localStorage 是另一种缓存 ajax 调用返回的数据的替代方法。所以,我创建了一个演示,localStorage它可以帮助其他可能想要使用localStorage而不是localCache缓存的人。

Ajax Call:

阿贾克斯调用:

$.ajax({
    type: "POST",
    dataType: 'json',
    contentType: "application/json; charset=utf-8",
    url: url,
    data: '{"Id":"' + Id + '"}',
    cache: true, //It must "true" if you want to cache else "false"
    //async: false,
    success: function (data) {
        var resData = JSON.parse(data);
        var Info = resData.Info;
        if (Info) {
            customerName = Info.FirstName;
        }
    },
    error: function (xhr, textStatus, error) {
        alert("Error Happened!");
    }
});

To store data into localStorage:

将数据存储到 localStorage:

$.ajaxPrefilter(function (options, originalOptions, jqXHR) {
if (options.cache) {
    var success = originalOptions.success || $.noop,
        url = originalOptions.url;

    options.cache = false; //remove jQuery cache as we have our own localStorage
    options.beforeSend = function () {
        if (localStorage.getItem(url)) {
            success(localStorage.getItem(url));
            return false;
        }
        return true;
    };
    options.success = function (data, textStatus) {
        var responseData = JSON.stringify(data.responseJSON);
        localStorage.setItem(url, responseData);
        if ($.isFunction(success)) success(responseJSON); //call back to original ajax call
    };
}
});

If you want to remove localStorage, use following statement wherever you want:

如果要删除 localStorage,请在任何地方使用以下语句:

localStorage.removeItem("Info");

Hope it helps others!

希望它能帮助别人!

回答by Paul Shan

All the modern browsers provides you storage apis. You can use them (localStorage or sessionStorage) to save your data.

所有现代浏览器都为您提供存储 API。您可以使用它们(localStorage 或 sessionStorage)来保存您的数据。

All you have to do is after receiving the response store it to browser storage. Then next time you find the same call, search if the response is saved already. If yes, return the response from there; if not make a fresh call.

您所要做的就是在收到响应后将其存储到浏览器存储中。然后下次找到相同的呼叫时,搜索是否已保存响应。如果是,则从那里返回响应;如果不打新电话。

Smartjaxplugin also does similar things; but as your requirement is just saving the call response, you can write your code inside your jQuery ajax success function to save the response. And before making call just check if the response is already saved.

Smartjax插件也做类似的事情;但由于您的要求只是保存调用响应,您可以在 jQuery ajax 成功函数中编写代码来保存响应。在拨打电话之前,只需检查响应是否已保存。

回答by spring

If I understood your question, here is the solution :

如果我理解你的问题,这里是解决方案:

    $.ajaxSetup({ cache: true});

and for specific calls

和特定的电话

 $.ajax({
        url: ...,
        type: "GET",
        cache: false,           
        ...
    });

If you want opposite (cache for specific calls) you can set false at the beginning and true for specific calls.

如果您想要相反(特定调用的缓存),您可以在开头设置 false 并为特定调用设置 true。

回答by I wrestled a bear once.

Old question, but my solution is a bit different.

老问题,但我的解决方案有点不同。

I was writing a single page web app that was constantly making ajax calls triggered by the user, and to make it even more difficult it required libraries that used methods other than jquery (like dojo, native xhr, etc). I wrote a plugin for one of my own librariesto cache ajax requests as efficiently as possible in a way that would work in all major browsers, regardless of which libraries were being used to make the ajax call.

我正在编写一个单页 Web 应用程序,该应用程序不断进行由用户触发的 ajax 调用,并且使其更加困难,它需要使用除 jquery 之外的方法的库(如 dojo、本机 xhr 等)。我为我自己的一个编写了一个插件,以一种可以在所有主要浏览器中工作的方式尽可能有效地缓存 ajax 请求,而不管使用哪些库来进行 ajax 调用。

The solution uses jSQL(written by me - a client-side persistent SQL implementation written in javascript which uses indexeddb and other dom storage methods), and is bundled with another library called XHRCreep(written by me) which is a complete re-write of the native XHR object.

该解决方案使用jSQL(由我编写 - 用 javascript 编写的客户端持久 SQL 实现,它使用 indexeddb 和其他 dom 存储方法),并与另一个名为XHRCreep(由我编写)的库捆绑在一起,该库完全重写了本机 XHR 对象。

To implement all you need to do is include the plugin in your page, which is here.

要实现所有您需要做的就是在您的页面中包含插件,这是在这里

There are two options:

有两种选择:

jSQL.xhrCache.max_time = 60;

Set the maximum age in minutes. any cached responses that are older than this are re-requested. Default is 1 hour.

以分钟为单位设置最大年龄。任何比这更旧的缓存响应都将被重新请求。默认为 1 小时。

jSQL.xhrCache.logging = true;

When set to true, mock XHR calls will be shown in the console for debugging.

设置为 true 时,模拟 XHR 调用将显示在控制台中以进行调试。

You can clear the cache on any given page via

您可以通过以下方式清除任何给定页面上的缓存

jSQL.tables = {}; jSQL.persist();

回答by user1634982

        function getDatas() {
            let cacheKey = 'memories';

            if (cacheKey in localStorage) {
                let datas = JSON.parse(localStorage.getItem(cacheKey));

                // if expired
                if (datas['expires'] < Date.now()) {
                    localStorage.removeItem(cacheKey);

                    getDatas()
                } else {
                    setDatas(datas);
                }
            } else {
                $.ajax({
                    "dataType": "json",
                    "success": function(datas, textStatus, jqXHR) {
                        let today = new Date();

                        datas['expires'] = today.setDate(today.getDate() + 7) // expires in next 7 days

                        setDatas(datas);

                        localStorage.setItem(cacheKey, JSON.stringify(datas));
                    },
                    "url": "http://localhost/phunsanit/snippets/PHP/json.json_encode.php",
                });
            }
        }

        function setDatas(datas) {
            // display json as text
            $('#datasA').text(JSON.stringify(datas));

            // your code here
           ....

        }

        // call
        getDatas();

enter link description here

在此处输入链接描述