web-dev-qa-db-fra.com

Quelles sont les techniques possibles pour mettre en cache une réponse Ajax en Javascript?

Je suis un gestionnaire de mise en œuvre de modules Javascript qui charge javascript fichiers via XHR objet. Le problème de cette méthode est la mise en cache des ressources:

  • Tout d'abord, XHR s'appuie sur un mécanisme de mise en cache du navigateur intégré qui fonctionne, mais son comportement dépend de la mise en œuvre du navigateur.
  • De plus, il existe une variable localStorage et un basket.js qui utilise localStorage pour mettre en cache les scripts téléchargés. Le problème réside dans la taille limitée de la mémoire, qui est généralement comprise entre 5 et 10 Mo. En outre, localStorage est un lieu partagé par de nombreux scripts qui l'utilisent également pour stocker des données.
  • Et il y a une interface Cache de l'API ServiceWorker, mais elle n'est disponible que dans le ServiceWorker runtime, de sorte qu'elle répond parfaitement à mes besoins.

Est-ce que quelqu'un connaît une technique de cache javascript intelligente ancienne ou nouvelle qu'il utilise dans son projet ou dont il a peut-être entendu parler?

Note : Ne proposez pas d'utiliser jQuery .ajax, qui est une interface avec XHR, ni avec aucune autre bibliothèque implémentant une interface avec des fonctionnalités Javascript intégrées.

Edit : Des propositions intéressantes ont été faites:

  • Utilisez la bibliothèque appelée localForage. La bibliothèque représente une API unifiée pour IndexedDB, WebSQL et localStorage, laquelle est utilisée dépend du navigateur.
  • Utilisez IndexedDB qui est un stockage vraiment puissant, sans limite d’espace importante. La seule préoccupation est que seuls les navigateurs modernes implémentent IndexedDB.
16
Eugene Tiurin

Ceci est spécifique à JQUERY ....

Votre pouvez faire ajax mis en place comme mis en cache.

    $.ajaxSetup({ cache: true});

et si pour des appels spécifiques vous ne voulez pas faire de réponse en cache, appelez

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

Si vous voulez en face (cache pour des appels spécifiques), vous pouvez définir false au début et true pour des appels spécifiques.

Si vous souhaitez stocker le résultat de la réponse ajax, vous pouvez utiliser le stockage local. Tous les navigateurs modernes vous fournissent des apis de stockage. Vous pouvez les utiliser (localStorage ou sessionStorage) pour enregistrer vos données.

Après réception de la réponse, stockez-la dans le stockage du navigateur. Ensuite, la prochaine fois que vous trouverez le même appel, recherchez si la réponse est déjà enregistrée. Si oui, retournez la réponse à partir de là; sinon faites un nouvel appel.

Smartjax plugin fait également des choses similaires; mais comme vos exigences ne font que sauvegarder la réponse à un appel, vous pouvez écrire votre code dans votre fonction de réussite jQuery ajax pour enregistrer la réponse. Et avant de passer un appel, vérifiez si la réponse est déjà enregistrée.

6
Somnath Muluk

Indexeddb étant une méthode utilisée pour stocker des données côté client, autorise les requêtes de base de données indexées.

Et ce sont les navigateurs pris en charge http://caniuse.com/#feat=indexeddb

Et ce sont les seuls problèmes

Firefox (prior to version 37) and Safari do not support IndexedDB inside web workers.
Not supported in Chrome for iOS or other iOS WebViews.

Chrome 36 and below did not support Blob objects as indexedDB values.

Voici un autre polyfill similaire que vous pouvez essayer , mais selon mon expérience (bien que limitée), les deux polyfill sont bogués/incomplets. Ils ont également beaucoup de problèmes en suspens sur GitHub où des personnes signalent des problèmes. Et lorsque j’ai testé l’un d’eux (j’oublie lequel), il était nettement plus lent que l’index natif IndexedDB.

Peut-être est-il possible de créer un polyfill décent, mais les actuels ne semblent pas faire le travail.

Devrais-je utiliser WebSQL qui était obsolète?

Le problème avec WebSQL est qu’il ne sera jamais supporté par IE ou Firefox. Vous pourriez probablement vous en tirer avec WebSQL si vous ne ciblez que les navigateurs mobiles, du moins jusqu'à ce que Firefox OS ou Windows Phone gagne une part de marché significative.

Est-il prévu de prendre en charge IndexedDB à l'avenir pour tous les navigateurs non pris en charge?

Soyons clairs. Vous parlez d'Apple, car tous les autres utilisateurs prennent en charge IndexedDB dans leur dernier navigateur (iOS Chrome utilise le moteur de rendu d'Apple, car Apple ne leur permet pas de faire autre chose).

Non seulement Apple ne prend pas en charge IndexedDB, mais ils n’ont rien dit publiquement (pour autant que je sache ... et j’ai fait pas mal de recherches). Ce qui semble assez étrange. Donc, autant que je sache, personne ne sait si Apple envisage de prendre en charge IndexedDB. Le théoricien du complot en moi pense peut-être qu'ils essaient de saboter les applications HTML5 pour forcer les gens à écrire des applications natives, mais ce n'est que pure spéculation.

Au total, cela laisse les développeurs dans une situation assez merdique. Il n'y a pas de bonne solution multiplateforme. Je vous recommande de vous plaindre à Apple à ce sujet. C'est ce que j'ai fait et j'ai demandé à mes utilisateurs qui souhaitent utiliser mon application basée sur IndexedDB sur iOS de faire de même. Toujours pas de mot d'Apple.

UPDATE - Indexeddb est désormais pris en charge dans iOS 8, comme indiqué dans WWDC 2014 - mais malheureusement il est cassé assez mal .

Considérant également que Subresource Integrity -

L'intégrité des sous-ressources permet aux navigateurs de vérifier que le fichier est livré sans manipulation imprévue.

N'a pas de connaissances? jusque là ?

Le je vais suggérer que vous pouvez aller avec

Sous-source solution basée si le mobile est votre cible principale

indexeddb si mobile n'est pas votre cible principale et utilisation des implémentations publiques disponibles pour mobile

Si tout ce qui précède vous semble trop complexe, alors

var localCache = {
    data: {},
    remove: function (url) {
        delete localCache.data[url];
    },
    //a cached version exists
    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); //log only!
        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);
    },
    timeout: 600, //in seconds
};

$.ajaxPrefilter(function (options, originalOptions, jqXHR) {
    if (options.cache) {
        var complete = originalOptions.complete || $.noop,
            url = originalOptions.url;
        //remove jQuery cache as you have your 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 = 'your url goes here';
    $('#ajaxButton').click(function (e) {
        $.ajax({
            url: url,
            data: {
                test: 'value'
            },
                cache: true,
                complete: doSomething
            });
        });
    });
    //ToDo after ajax call finishes, or cached version retrived
    function doSomething(data) {
        console.log(data);
    }

Une autre réponse spécifique de JQUERY?

Pas sûr que cela réponde à votre question mais cela pourrait aider. Il met en cache les appels ajax avec un délai d'attente.

Dans le préfiltrage, répertoriez les différents appels PHP ajax que vous souhaitez ajouter pour la mise en cache. Dans cet exemple, le cache est activé avec un délai d'expiration de 10 minutes.

/*----------------------------*/
/* set ajax caching variables */
/*----------------------------*/
$.set_Ajax_Cache_filters = function () {
    var localCache = {
        timeout: 600000, // 10 minutes
        data: {}, //@type {{_: number, 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) {
            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);
        }
    };

    /*----------------------*/
    /* set ajax pre filters */
    /*----------------------*/
    $.ajaxPrefilter(function (options, originalOptions, jqXHR) {
        // list of allowed url to cache
        if (url !== '..............file.php') {
            return false;
        }
        if (options.cache) {
            var complete = originalOptions.complete || $.noop,
                    url = originalOptions.url;

            options.cache = false;//remove jQuery cache using proprietary one
            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);
            };
        }
    });
};
2
cpugourou

Pour ce faire, la meilleure technique consiste à utiliser le cache local, ajaxPrefilter et l'option de cache ajax. La combinaison de ces trois éléments vous permettra de créer le cache que vous souhaitez, que vous pouvez facilement contrôler. Voici un exemple de code:

var localCache = {
    data: {},
    remove: function (url) {
        delete localCache.data[url];
    },
    //a cached version exists
    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); //log only!
        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);
    },
    timeout: 600, //in seconds
};

$.ajaxPrefilter(function (options, originalOptions, jqXHR) {
    if (options.cache) {
        var complete = originalOptions.complete || $.noop,
            url = originalOptions.url;
        //remove jQuery cache as you have your 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 = 'your url goes here';
    $('#ajaxButton').click(function (e) {
        $.ajax({
            url: url,
            data: {
                test: 'value'
            },
                cache: true,
                complete: doSomething
            });
        });
    });
    //ToDo after ajax call finishes, or cached version retrived
    function doSomething(data) {
        console.log(data);
    }

Profitez de votre codage

1
Omar El Don

Essayez cela pourrait fonctionner

    var cache = {};
var formatTweets(info) {  
    //formats tweets, does whatever you want with the Tweet information
};

//event
$('myForm').addEvent('submit',function() {
    var handle = $('handle').value; //davidwalshblog, for example
    var cacheHandle = handle.toLowerCase();
    if(cache[cacheHandle] != "undefined") {
        formatTweets(cache[cacheHandle]);
    }
    else {
        //gitter
        var myTwitterGitter = new TwitterGitter(handle,{
            count: 10,
            onComplete: function(tweets,user) {
                cache[cacheHandle] = tweets;
                formatTweets(tweets);
            }
        }).retrieve();
    }
});
0
Faisal