it-swarm.com.de

Zwischenspeichern einer JQuery Ajax-Antwort in Javascript / Browser

Ich möchte das Caching einer Ajax-Antwort in Javascript/Browser aktivieren.

Aus den jquery.ajax docs :

Standardmäßig werden Anforderungen immer ausgegeben, aber der Browser liefert möglicherweise Ergebnisse aus dem Cache. Wenn Sie die Verwendung der zwischengespeicherten Ergebnisse nicht zulassen möchten, setzen Sie den Cache auf false. Wenn die Anforderung einen Fehler melden soll, wenn das Asset seit der letzten Anforderung nicht geändert wurde, setzen Sie ifModified auf true.

Keine dieser Adressen erzwingt jedoch das Zwischenspeichern.

Motivation: Ich möchte $.ajax({...}) Aufrufe in meine Initialisierungsfunktionen einfügen, von denen einige dieselbe URL anfordern. Manchmal muss ich eine dieser Initialisierungsfunktionen aufrufen, manchmal rufe ich mehrere auf.

Ich möchte also die Anforderungen an den Server minimieren, wenn diese bestimmte URL bereits geladen wurde.

Ich könnte meine eigene Lösung rollen (mit einigen Schwierigkeiten!), Aber ich würde gerne wissen, ob es eine Standardmethode dafür gibt.

89
cammil

cache:true funktioniert nur mit GET und HEAD request.

Sie könnten Ihre eigene Lösung entwickeln, wie Sie gesagt haben, mit etwas in dieser Richtung:

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

Funktioniert hier

BEARBEITEN: Da dieser Beitrag immer beliebter wird, finden Sie hier eine noch bessere Antwort für diejenigen, die den Timeout-Cache verwalten möchten und sich auch nicht mit dem ganzen Durcheinander in $. Ajax () as befassen müssen Ich benutze $. AjaxPrefilter () . Jetzt nur noch {cache: true} reicht aus, um den Cache korrekt zu behandeln:

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

nd die Geige hier ACHTUNG, nicht mit $ .Deferred arbeiten

Hier ist eine funktionierende, aber fehlerhafte Implementierung, die mit Aufgeschoben arbeitet:

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 In einigen Fällen ist unsere Cache-ID von der JSON-Objektdarstellung in json2 lib abhängig.

Verwenden Sie die Konsolenansicht (F12) oder FireBug, um einige vom Cache generierte Protokolle anzuzeigen.

135
TecHunter

Ich habe nach einem Caching für meinen Phonegap-App-Speicher gesucht und die Antwort von @TecHunter gefunden. Das ist großartig, aber mit localCache erledigt.

Ich fand und lernte, dass localStorage eine weitere Alternative ist, um die von einem Ajax-Aufruf zurückgegebenen Daten zwischenzuspeichern. Also habe ich eine Demo mit localStorage erstellt, die anderen helfen wird, die localStorage anstelle von localCache zum Cachen verwenden möchten.

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

m Daten in localStorage zu speichern:

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

Wenn Sie localStorage entfernen möchten, verwenden Sie die folgende Anweisung, wo immer Sie möchten:

localStorage.removeItem("Info");

Hoffe es hilft anderen!

10
Mayank Modi

Alle modernen Browser bieten Speicher-APIs. Sie können sie verwenden (localStorage oder sessionStorage), um Ihre Daten zu speichern.

Alles, was Sie tun müssen, ist nach Erhalt der Antwort diese im Browser-Speicher zu speichern. Wenn Sie dann das nächste Mal denselben Anruf finden, suchen Sie, ob die Antwort bereits gespeichert ist. Wenn ja, geben Sie die Antwort von dort zurück. Wenn nicht, tätigen Sie einen neuen Anruf.

Smartjax Plugin macht auch ähnliche Dinge; Da Ihre Anforderung jedoch nur das Speichern der Anrufantwort ist, können Sie Ihren Code in Ihre jQuery-Ajax-Erfolgsfunktion schreiben, um die Antwort zu speichern. Und bevor Sie einen Anruf tätigen, überprüfen Sie einfach, ob die Antwort bereits gespeichert ist.

8
Paul Shan

Wenn ich Ihre Frage verstanden habe, ist hier die Lösung:

    $.ajaxSetup({ cache: true});

und für bestimmte Anrufe

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

Wenn Sie das Gegenteil wünschen (Cache für bestimmte Anrufe), können Sie am Anfang false und für bestimmte Anrufe true festlegen.

5
spring

Alte Frage, aber meine Lösung ist ein bisschen anders.

Ich habe eine einseitige Web-App geschrieben, die ständig vom Benutzer ausgelöste Ajax-Aufrufe ausführt. Um dies noch schwieriger zu machen, waren Bibliotheken erforderlich, die andere Methoden als jquery verwendeten (wie Dojo, native xhr usw.). Ich habe ein Plugin für eine von meine eigenen Bibliotheken geschrieben, um Ajax-Anforderungen so effizient wie möglich zu cachen, so dass dies in allen gängigen Browsern funktioniert, unabhängig davon, welche Bibliotheken für den Ajax-Aufruf verwendet wurden.

Die Lösung verwendet jSQL (von mir geschrieben - eine clientseitige persistente SQL-Implementierung in Javascript, die indexeddb und andere dom-Speichermethoden verwendet) und wird mit einer anderen Bibliothek namens XHRCreep gebündelt = (von mir geschrieben) Dies ist ein vollständiges Umschreiben des nativen XHR-Objekts.

Um alles zu implementieren, was Sie tun müssen, ist das Plugin in Ihre Seite aufzunehmen, welches hier ist .

Es gibt zwei Möglichkeiten:

jSQL.xhrCache.max_time = 60;

Stellen Sie das maximale Alter in Minuten ein. Alle zwischengespeicherten Antworten, die älter als diese sind, werden erneut angefordert. Standard ist 1 Stunde.

jSQL.xhrCache.logging = true;

Wenn diese Option auf "true" gesetzt ist, werden in der Konsole falsche XHR-Aufrufe zum Debuggen angezeigt.

Sie können den Cache auf jeder Seite über löschen

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