자바 스크립트 / 브라우저에서 jquery ajax 응답 캐싱


96

javascript / browser에서 ajax 응답의 캐싱을 활성화하고 싶습니다.

로부터 jquery.ajax 워드 프로세서 :

기본적으로 요청은 항상 발행되지만 브라우저는 캐시에서 결과를 제공 할 수 있습니다. 캐시 된 결과의 사용을 허용하지 않으려면 cache를 false로 설정하십시오. 마지막 요청 이후 자산이 수정되지 않은 경우 요청이 실패를보고하도록하려면 ifModified를 true로 설정하십시오.

그러나 이러한 주소 중 어느 것도 캐싱을 강제하지 않습니다.

동기 부여 :$.ajax({...}) 일부는 동일한 URL을 요청하는 초기화 함수 에 호출 을 넣고 싶습니다 . 때로는 이러한 초기화 함수 중 하나를 호출해야하며 때로는 여러 개를 호출합니다.

따라서 특정 URL이 이미로드 된 경우 서버에 대한 요청을 최소화하고 싶습니다.

나는 내 자신의 솔루션을 굴릴 수 있지만 (어려움이 있습니다!), 이것을 수행하는 표준 방법이 있는지 알고 싶습니다.


이미로드 한 URL을 추적하고 해당 목록에 대한 결과를 저장하는 것이 어렵다고 생각하지 않았을 것입니다. 그런 다음 AJAX 호출을하기 전에 URL을 확인할 수 있습니다. Voila-자신 만의 기본 캐시가 있습니다.

서버의 응답에 cache-control 및 만료 헤더를 추가 할 수 있으므로 해당 값에서 구성한 시간 초과 후에 만 ​​서버를 호출해야합니다
hereandnow78

답변:


142

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

여기서 작업하는 바이올린

편집 :이 게시물이 인기를 얻음 에 따라 시간 초과 캐시를 관리하려는 사람들에게 더 나은 답변이 있으며 $ .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);
}

그리고 여기 바이올린 은 $ .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
            });
        });
    });
});

Fiddle HERE 일부 문제, 캐시 ID는 json2 lib JSON 객체 표현에 따라 다릅니다.

콘솔보기 (F12) 또는 FireBug를 사용하여 캐시에서 생성 된 일부 로그를보십시오.


localCache.set함수에 콜백을 넣는 이유가 있습니까? 단순히 doSomehing(jqXHR)캐시를 설정 한 후에는 어떻습니까?
cammil

나는 단지 이런 식으로 그것을 선호한다 그래서 나는 같은 것을 할 필요가 doSomething(localCache.set(url,jqXHR));없지만 단지
개인적인

2
$ .ajax를 약속으로 사용하는 것을 지원하기 위해 이것을 개선하기위한 제안이 있습니까? beforeSend에서 false를 반환하면 요청이 취소되므로 기존 $ .ajax (...). done (function (response) {...}). fail (...)이 이제 실패가 호출되기 때문에 작동을 중지합니다. 이상은 다 ... 그리고 나는 그들에게 모든 :( 재 작성하지 않고 것
franck102

2
@TecHunter 이것에 대해 정말 감사합니다. 세 가지 더 약간의 개선이있을 수 있습니다. 첫째, 동일한 리소스에 대해 동시에 여러 요청이 이루어지면 모두 캐시를 놓치게됩니다. 이 문제를 해결하려면 특정 "id"에 대한 캐시를 첫 번째 요청에서 보류로 설정하고 첫 번째 요청이 돌아올 때까지 후속 요청에 대한 결과 전송을 연기 할 수 있습니다. 둘째, 동일한 리소스에 대한 모든 요청이 동일한 결과를 얻도록 요청의 오류 결과를 캐시 할 수 있습니다.
mjhm

2
@TecHunter-좋은 솔루션,이 솔루션을 중요한 변경 사항으로 사용했습니다. 캐시 된 객체가 다른 함수에서 수정되면 문제가 발생하므로 캐시 된 객체를 설정하고 가져 오는 동안 아래와 같이 해당 객체의 복사본을 반환합니다. localCache.data[url] = { _: new Date().getTime(), data: _.cloneDeep(cachedData, true) }; _.cloneDeep(localCache.data[url].data, true)
Bharat Patil

12

내 phonegap 앱 스토리지에 대한 캐싱을 찾고 있었고 @TecHunter의 답변을 찾았지만 localCache.

나는 localStorage가 ajax 호출에 의해 반환 된 데이터를 캐시하는 또 다른 대안임을 발견하고 알게되었습니다. 그래서 저는 캐싱 대신 localStorage사용하고자하는 다른 사람들에게 도움이 될 하나의 데모를 만들었습니다 .localStoragelocalCache

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

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

localStorage를 제거하려면 원하는 곳에서 다음 문을 사용하십시오.

localStorage.removeItem("Info");

다른 사람들에게 도움이되기를 바랍니다!


안녕,에서 localStorage.removeItem("Info");의에 대해 "info"그 URL입니다?
vsogrimen

@vsogrimen info은 localStorage에 데이터를 저장하는 개체입니다.
immayankmodi

1
계속 responseJSON is not defined. 이 문제를 해결할 방법이 있습니까? (내 데이터 형식은 HTML입니다)
니키타 웃

@CreativeMind, reponseJOSN 제거 및 "var responseData = JSON.stringify (data);"사용 대신 success (data)로
똑같이하십시오

여러 요청에 대해 캐시가 필요하므로 localStorage를 선호합니다.
KeitelDOG

9

모든 최신 브라우저는 스토리지 API를 제공합니다. 그것들 (localStorage 또는 sessionStorage)을 사용하여 데이터를 저장할 수 있습니다.

응답을받은 후 브라우저 저장소에 저장하기 만하면됩니다. 그런 다음 다음에 동일한 통화를 찾을 때 응답이 이미 저장되어 있는지 검색하십시오. 그렇다면 거기에서 응답을 반환하십시오. 새로운 전화를 걸지 않으면.

Smartjax 플러그인도 비슷한 작업을 수행합니다. 그러나 요구 사항은 호출 응답을 저장하는 것이므로 jQuery ajax 성공 함수 내에 코드를 작성하여 응답을 저장할 수 있습니다. 그리고 전화를 걸기 전에 응답이 이미 저장되어 있는지 확인하십시오.


IndexedDB에 저장된 응답이 있는데 IndexedDB를 확인하는 방법이 있습니까? 또한 Session Storage를 사용하는 경우 응답이 있는지 여부를 jQuery를 사용하지 않는지 확인하는 방법이 있습니다. jQuery 이외의 라이브러리를 포함 할 수 없습니다. 감사합니다,
Abhishek 가르 왈

7

귀하의 질문을 이해했다면 여기에 해결책이 있습니다.

    $.ajaxSetup({ cache: true});

및 특정 통화

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

반대 (특정 호출에 대한 캐시)를 원하면 처음에 false를 설정하고 특정 호출에 대해 true를 설정할 수 있습니다.


2
그와 정반대이다
TecHunter

그것은 나를 위해 작동합니다, 감사합니다! 내 페이지에서 캐싱이 기본적으로 활성화되지 않은 것이 이상합니다.
Timur Nurlygayanov

2

오래된 질문이지만 내 솔루션은 약간 다릅니다.

사용자에 의해 트리거되는 아약스 호출을 지속적으로 수행하는 단일 페이지 웹 앱을 작성하고 있었고이를 더욱 어렵게 만들기 위해 jquery 이외의 메서드 (dojo, 기본 xhr 등)를 사용하는 라이브러리가 필요했습니다. 내 라이브러리 중 하나에 대한 플러그인 을 작성하여 ajax 호출에 사용 된 라이브러리에 관계없이 모든 주요 브라우저에서 작동하는 방식으로 가능한 한 효율적으로 ajax 요청을 캐시했습니다.

이 솔루션은 jSQL (내가 작성한-indexeddb 및 기타 dom 저장 방법을 사용하는 자바 스크립트로 작성된 클라이언트 측 영구 SQL 구현)을 사용하며 XHRCreep (내가 작성한) 라는 다른 라이브러리와 함께 번들로 제공됩니다. 네이티브 XHR 객체.

수행해야 할 모든 작업을 구현하려면 여기에있는 페이지에 플러그인을 포함하면 됩니다 .

두 가지 옵션이 있습니다.

jSQL.xhrCache.max_time = 60;

최대 연령 (분)을 설정합니다. 이보다 오래된 캐시 된 응답은 다시 요청됩니다. 기본값은 1 시간입니다.

jSQL.xhrCache.logging = true;

true로 설정하면 디버깅을 위해 모의 XHR 호출이 콘솔에 표시됩니다.

주어진 페이지에서 캐시를 지울 수 있습니다.

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

github 및 공식 웹 사이트에서 플러그인을 찾을 수 없습니다. 답변을 업데이트하십시오 플러그인이 필요합니다 :) github에서 귀하의 추종자입니다. 잘 했어;) @ occams - 면도기
알리 칸 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();

여기에 링크 설명 입력

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.