Lưu vào bộ đệm một phản hồi ajax jquery trong javascript / browser


96

Tôi muốn bật bộ nhớ đệm của phản hồi ajax trong javascript / browser.

Từ tài liệu jquery.ajax :

Theo mặc định, các yêu cầu luôn được đưa ra, nhưng trình duyệt có thể cung cấp kết quả từ bộ nhớ cache của nó. Để không cho phép sử dụng các kết quả đã lưu trong bộ nhớ cache, hãy đặt bộ nhớ cache thành false. Để khiến yêu cầu báo cáo không thành công nếu nội dung chưa được sửa đổi kể từ lần yêu cầu cuối cùng, hãy đặt ifModified thành true.

Tuy nhiên, cả hai địa chỉ này đều không buộc lưu vào bộ nhớ đệm.

Động lực: Tôi muốn đặt $.ajax({...})các cuộc gọi vào các hàm khởi tạo của mình, một số trong số đó yêu cầu cùng một url. Đôi khi tôi cần gọi một trong những hàm khởi tạo này, đôi khi tôi gọi một vài hàm.

Vì vậy, tôi muốn giảm thiểu các yêu cầu đến máy chủ nếu url cụ thể đó đã được tải.

Tôi có thể đưa ra giải pháp của riêng mình (với một số khó khăn!), Nhưng tôi muốn biết liệu có một cách tiêu chuẩn để thực hiện việc này hay không.


Tôi sẽ không nghĩ rằng sẽ gặp khó khăn khi theo dõi những URL nào bạn đã tải và lưu trữ kết quả dựa trên danh sách đó. Sau đó, bạn có thể kiểm tra các URL của mình trước khi thực hiện cuộc gọi AJAX. Thì đấy - bạn có bộ nhớ cache cơ bản của riêng mình.

bạn có thể thêm bộ nhớ cache kiểm soát và hết hạn tiêu đề để trả lời của bạn trên máy chủ, do đó máy chủ của bạn chỉ nên được gọi sau khi thời gian chờ bạn cấu hình trong đó các giá trị
hereandnow78

Câu trả lời:


141

cache:true chỉ hoạt động với yêu cầu GET và HEAD.

Bạn có thể đưa ra giải pháp của riêng mình như bạn đã nói với những điều gì đó dọc theo những dòng sau:

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

Làm việc ở đây

CHỈNH SỬA: khi bài đăng này trở nên phổ biến, đây là một câu trả lời thậm chí còn tốt hơn cho những người muốn quản lý bộ nhớ cache thời gian chờ và bạn cũng không phải bận tâm đến tất cả những thứ lộn xộn trong $ .ajax () khi tôi sử dụng $ .ajaxPrefilter () . Bây giờ chỉ cần thiết lập {cache: true}là đủ để xử lý bộ nhớ cache một cách chính xác:

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

Và vấn đề ở đây là CẨN THẬN, không hoạt động với $ .Deferred

Đây là một triển khai đang hoạt động nhưng có sai sót khi bị hoãn:

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

Chơi thử TẠI ĐÂY Một số vấn đề, ID bộ nhớ cache của chúng tôi phụ thuộc vào biểu diễn đối tượng json2 lib JSON.

Sử dụng chế độ xem Console (F12) hoặc FireBug để xem một số nhật ký được tạo bởi bộ đệm.


có lý do gì bạn đặt một lệnh gọi lại trên localCache.sethàm? Tại sao không chỉ đơn giản là doSomehing(jqXHR)sau khi thiết lập bộ nhớ cache?
cammil

Tôi chỉ thích nó theo cách này vì vậy tôi không cần phải làm điều gì đó giống như doSomething(localCache.set(url,jqXHR));nhưng nó chỉ là sở thích personnal
TecHunter

2
Bất kỳ đề xuất nào để cải thiện điều này để hỗ trợ sử dụng $ .ajax như một lời hứa? Trả về false từ beforeSend hủy yêu cầu (nếu cần) vì vậy hiện tại $ .ajax (...). Done (function (response) {...}). Fail (...) hiện ngừng hoạt động vì fail được gọi đúng hơn hơn làm ... và tôi không muốn viết lại tất cả chúng :(
franck102

2
@TecHunter Cảm ơn rất nhiều vì điều này. Ba cải tiến nhỏ nữa có thể được thực hiện. Đầu tiên, nếu nhiều yêu cầu được thực hiện cho cùng một tài nguyên cùng một lúc, tất cả chúng sẽ bỏ sót bộ nhớ cache. Để khắc phục điều này, bạn có thể muốn đặt bộ nhớ cache cho một "id" nhất định thành đang chờ xử lý với yêu cầu đầu tiên và trì hoãn việc gửi kết quả cho các yêu cầu tiếp theo cho đến khi yêu cầu đầu tiên quay trở lại. Thứ hai, bạn có thể muốn lưu kết quả lỗi của một yêu cầu vào bộ nhớ cache để tất cả các yêu cầu cho cùng một tài nguyên nhận được cùng một kết quả.
mjhm

2
@TecHunter - Giải pháp tuyệt vời, tôi đã sử dụng giải pháp này với một thay đổi quan trọng. Nếu đối tượng lưu trữ đang được sửa đổi trong các chức năng khác, nó sẽ gây ra vấn đề, vì vậy trong khi thiết bị lưu trữ và đối tượng, tôi trở về bản sao của đối tượng đó như hình dưới đây: localCache.data[url] = { _: new Date().getTime(), data: _.cloneDeep(cachedData, true) }; _.cloneDeep(localCache.data[url].data, true)
Bharat Patil

11

Tôi đang tìm kiếm bộ nhớ đệm để lưu trữ ứng dụng bản đồ điện thoại của mình và tôi đã tìm thấy câu trả lời của @TecHunter là tuyệt vời nhưng đã sử dụng xong localCache.

Tôi đã tìm thấy và biết rằng localStorage là một giải pháp thay thế khác để lưu vào bộ đệm dữ liệu được trả về bởi lệnh gọi ajax. Vì vậy, tôi đã tạo một bản demo bằng cách sử dụng localStoragenó sẽ giúp những người khác có thể muốn sử dụng localStoragethay vì localCachecho bộ nhớ đệm.

Cuộc gọi Ajax:

$.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!");
    }
});

Để lưu trữ dữ liệu vào 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
    };
}
});

Nếu bạn muốn xóa localStorage, hãy sử dụng câu lệnh sau ở bất cứ đâu bạn muốn:

localStorage.removeItem("Info");

Hy vọng nó sẽ giúp những người khác!


Xin chào, trong localStorage.removeItem("Info");, về "info"nó có phải là url không?
vsogrimen

@vsogrimen infolà đối tượng để lưu trữ dữ liệu trong localStorage.
immayankmodi

1
tiếp tục nhận được responseJSON is not defined. Bất kỳ cách nào để khắc phục điều này? (loại dữ liệu của tôi là html)
Nikita 웃

@CreativeMind, xóa reponseJOSN và sử dụng "var responseData = JSON.stringify (data);" thay vào đó, hãy làm điều tương tự để thành công (dữ liệu)
Unicco

Tôi thích localStorage hơn vì tôi cần bộ nhớ cache trên nhiều yêu cầu.
KeitelDOG

9

Tất cả các trình duyệt hiện đại đều cung cấp cho bạn apis lưu trữ. Bạn có thể sử dụng chúng (localStorage hoặc sessionStorage) để lưu dữ liệu của mình.

Tất cả những gì bạn phải làm là sau khi nhận được phản hồi, hãy lưu trữ nó vào bộ nhớ của trình duyệt. Sau đó, lần tới khi bạn tìm thấy cuộc gọi tương tự, hãy tìm kiếm xem phản hồi đã được lưu chưa. Nếu có, hãy trả lại phản hồi từ đó; nếu không thực hiện một cuộc gọi mới.

Plugin Smartjax cũng làm những điều tương tự; nhưng vì yêu cầu của bạn là chỉ lưu phản hồi cuộc gọi, bạn có thể viết mã của mình bên trong hàm thành công ajax của jQuery để lưu phản hồi. Và trước khi thực hiện cuộc gọi, chỉ cần kiểm tra xem phản hồi đã được lưu chưa.


Tôi có các câu trả lời được lưu trong IndexedDB, có cách nào để kiểm tra IndexedDB không? Ngoài ra, nếu tôi sử dụng Session Storage thì có cách nào để kiểm tra xem phản hồi có xuất hiện hay không bằng cách sử dụng jQuery. Tôi không thể bao gồm bất kỳ thư viện nào ngoài jQuery. Cảm ơn,
Abhishek Aggarwal

7

Nếu tôi hiểu câu hỏi của bạn, đây là giải pháp:

    $.ajaxSetup({ cache: true});

và cho các cuộc gọi cụ thể

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

Nếu bạn muốn ngược lại (bộ nhớ cache cho các cuộc gọi cụ thể), bạn có thể đặt false ở đầu và true cho các cuộc gọi cụ thể.


2
đó là hoàn toàn ngược lại
TecHunter

Nó làm việc cho tôi, cảm ơn bạn! Thật kỳ lạ là bộ nhớ đệm không được bật theo mặc định trên trang của tôi ..
Timur Nurlygayanov

2

Câu hỏi cũ, nhưng giải pháp của tôi là một chút khác nhau.

Tôi đang viết một ứng dụng web trên một trang liên tục thực hiện các lệnh gọi ajax do người dùng kích hoạt và để gây khó khăn hơn nữa, nó yêu cầu các thư viện sử dụng các phương thức khác với jquery (như dojo, native xhr, v.v.). Tôi đã viết một plugin cho một trong các thư viện của riêng mình để lưu vào bộ nhớ cache các yêu cầu ajax hiệu quả nhất có thể theo cách hoạt động trong tất cả các trình duyệt chính, bất kể thư viện nào đang được sử dụng để thực hiện lệnh gọi ajax.

Giải pháp sử dụng jSQL (do tôi viết - một triển khai SQL liên tục phía máy khách được viết bằng javascript sử dụng indexeddb và các phương thức lưu trữ dom khác) và được đóng gói với một thư viện khác có tên là XHRCreep (do tôi viết), là bản viết lại hoàn chỉnh của đối tượng XHR gốc.

Để triển khai tất cả những gì bạn cần làm là đưa plugin vào trang của bạn, ở đây .

Có hai lựa chọn:

jSQL.xhrCache.max_time = 60;

Đặt tuổi tối đa tính bằng phút. mọi câu trả lời đã lưu trong bộ nhớ cache cũ hơn câu trả lời này sẽ được yêu cầu lại. Mặc định là 1 giờ.

jSQL.xhrCache.logging = true;

Khi được đặt thành true, các lệnh gọi XHR giả sẽ được hiển thị trong bảng điều khiển để gỡ lỗi.

Bạn có thể xóa bộ nhớ cache trên bất kỳ trang nào thông qua

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

Tôi không thể tìm thấy plugin của bạn trong github và trang web chính thức. Vui lòng cập nhật câu trả lời của bạn Tôi cần plugin của bạn :) Tôi là người theo dõi bạn trên github. Good job;) @ occams-dao cạo
Alican Kablan

-1
        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();

nhập mô tả liên kết ở đây

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.