Cet article a été écrit par l'auteur invité Peter Bengtsson. Le post d'invité spécial de SitePoint est conçu pour vous apporter un excellent contenu d'écrivains et de conférenciers bien connus dans la communauté JavaScript
Cet article montre comment implémenter un cache local de demandes récupérées afin que si elle est exécutée à plusieurs reprises, elle sera lue dans le magasin de session. L'avantage est que vous n'avez pas besoin d'écrire de code personnalisé pour chaque ressource que vous souhaitez cache.
Si vous souhaitez montrer votre prochaine fête JavaScript et montrer vos différentes compétences en matière de promesse, des API de pointe et un stockage local, lisez la suite.
cachedFetch
encapsule les appels standard fetch
, qui peuvent automatiquement mettre en cache les réponses en fonction du type de contenu et de l'URL, ce qui rend le mécanisme de cache universel. cachedFetch
incluent la gestion des tubes de cache à partir du stockage de session avant de faire une demande de réseau, et la gestion du contenu a expiré pour éviter d'utiliser des données obsolètes. À ce stade, vous devriez être familier avec Fetch. Il s'agit d'une nouvelle API native dans le navigateur pour remplacer l'ancienne API XMLHTTPREQUEST.
Puis-je utiliser Fetch? https://www.php.cn/link/B751EA087892EBECA363034301f45c69 sur le site Web sur le support principal du navigateur pour la fonction Fetch.
Bien que tous les navigateurs ne soient pas parfaitement mis en œuvre, vous pouvez utiliser le polyfill Fetch de GitHub (il y a des spécifications standard ici si vous ne faites rien toute la journée).
Supposons que vous sachiez exactement quelle ressource vous devez télécharger et que vous ne souhaitez le télécharger qu'une seule fois. Vous pouvez utiliser les variables globales comme cache comme suit:
let origin = null; fetch('https://httpbin.org/get') .then(r => r.json()) .then(information => { origin = information.origin; // 您的客户端IP }); // 需要延迟以确保fetch已完成 setTimeout(() => { console.log('您的来源是 ' + origin); }, 3000);
Cela ne dépend que des variables globales pour contenir des données mises en cache. Le problème direct est que si vous rechargez la page ou naviguez vers une nouvelle page, les données mises en cache disparaîtront.
Avant de disséquer ses lacunes, mettons à niveau la première solution simple.
fetch('https://httpbin.org/get') .then(r => r.json()) .then(info => { sessionStorage.setItem('information', JSON.stringify(info)); }); // 需要延迟以确保fetch已完成 setTimeout(() => { let info = JSON.parse(sessionStorage.getItem('information')); console.log('您的来源是 ' + info.origin); }, 3000);
Le premier problème direct est que la fetch est basée sur la promesse, ce qui signifie que nous ne pouvons pas déterminer quand cela sera fait, donc par souci de certitude, nous ne devons pas compter sur son exécution jusqu'à ce que ses promesses analysent.
Le deuxième problème est que cette solution est très spécifique aux URL spécifiques et aux extraits de données mis en cache spécifiques (informations clés dans cet exemple). Ce que nous voulons, c'est une solution basée sur une URL universelle.
Créons un emballage autour de Fetch qui renvoie également une promesse. Le code qui l'appelle peut ne pas se soucier de savoir si le résultat provient du réseau ou du cache local.
alors imaginez que vous a l'habitude de faire ceci:
let origin = null; fetch('https://httpbin.org/get') .then(r => r.json()) .then(information => { origin = information.origin; // 您的客户端IP }); // 需要延迟以确保fetch已完成 setTimeout(() => { console.log('您的来源是 ' + origin); }, 3000);
fetch('https://httpbin.org/get') .then(r => r.json()) .then(info => { sessionStorage.setItem('information', JSON.stringify(info)); }); // 需要延迟以确保fetch已完成 setTimeout(() => { let info = JSON.parse(sessionStorage.getItem('information')); console.log('您的来源是 ' + info.origin); }, 3000);
Commençons par le code qui enveloppe simplement la fonction de fetch:
fetch('https://httpbin.org/get') .then(r => r.json()) .then(issues => { console.log('您的来源是 ' + info.origin); });
cachedFetch('https://httpbin.org/get') .then(r => r.json()) .then(info => { console.log('您的来源是 ' + info.origin); });
La première promesse renvoyée par Fetch continuera en fait à effectuer la demande GET. S'il y a un problème avec CORS (partage de ressources croisées), les méthodes .text (), .json () ou .blob () ne fonctionneront pas.
La fonctionnalité la plus intéressante est que nous devons
cloner l'objet de réponse renvoyé par la première promesse. Si nous ne le faisons pas, nous nous sur-injectons, et lorsque les utilisateurs finaux de Promise essaient d'appeler .json () (par exemple), ils obtiennent cette erreur:Une autre chose à noter est la gestion minutieuse du type de réponse: nous ne stockons la réponse que lorsque le code d'état est de 200 et que le type de contenu est l'application / JSON ou le texte / *. En effet, SessionStorage ne peut stocker que du texte.
const cachedFetch = (url, options) => { return fetch(url, options); };
La chose intelligente à propos de cette solution à ce jour est qu'elle fonctionne sans interférer avec les demandes JSON
etHTML. Lorsqu'il s'agit d'une image, il n'essaie pas de le stocker dans SessionStorage.
const cachedFetch = (url, options) => { // 使用URL作为sessionStorage的缓存键 let cacheKey = url; return fetch(url, options).then(response => { // 让我们只在内容类型为JSON或非二进制内容时存储在缓存中 let ct = response.headers.get('Content-Type'); if (ct && (ct.match(/application\/json/i) || ct.match(/text\//i))) { // 有一个.json()而不是.text(),但我们将它存储在sessionStorage中作为字符串。 // 如果我们不克隆响应,它将在返回时被使用。这样我们就可以不干扰。 response.clone().text().then(content => { sessionStorage.setItem(cacheKey, content); }); } return response; }); };
Par conséquent, notre première implémentation n'est responsable que du stockage de la réponse de la demande. Cependant, si vous appelez CachedFetch la deuxième fois, il n'essaiera toujours pas de récupérer quoi que ce soit de SessionStorage . Ce que nous devons faire est de retourner une promesse, et la promesse doit analyser un objet de réponse.
Exemple de codepen
ça marche!
<code>TypeError: Body has already been consumed.</code>
Pour voir comment il fonctionne réellement, ouvrez le codep de ce code, puis ouvrez l'onglet "réseau" du navigateur dans les outils du développeur. Appuyez plusieurs fois sur le bouton d'exécution (le coin supérieur droit de Codepen) et vous devriez voir que seules les images demandent à plusieurs reprises sur le réseau.
L'une des intelligences de cette solution est le manque de "pâtes de rappel". Étant donné que l'appel SessionStorage.getItem est synchrone (c'est-à-dire le blocage), nous n'avons pas à traiter "est-ce dans le stockage local?" Et nous ne rendrons les résultats mis en cache que s'il y a du contenu. Sinon, l'instruction IF continuera uniquement à exécuter le code ordinaire.
Jusqu'à présent, nous utilisons SessionStorage, c'est comme LocalStorage, juste que SessionStorage est effacé lorsque vous démarrez un nouvel onglet. Cela signifie que nous tirons parti d'un "moyen naturel" pour éviter le temps de cache trop longtemps. Si nous utilisons localStorage à la place et mettons en cache quelque chose, il restera toujours coincé même si le contenu distant a changé, ce qui est mauvais.
Une meilleure solution consiste à laisser le contrôle de l'utilisateur . (Dans ce cas, l'utilisateur est le développeur Web qui utilise notre fonction CachedFetch). Tout comme Memcached ou Redis Storage côté serveur, vous pouvez définir une durée de vie qui spécifie la durée de la mise en cache.
par exemple, dans Python (en utilisant Flask):
let origin = null; fetch('https://httpbin.org/get') .then(r => r.json()) .then(information => { origin = information.origin; // 您的客户端IP }); // 需要延迟以确保fetch已完成 setTimeout(() => { console.log('您的来源是 ' + origin); }, 3000);
Maintenant, ni SessionStorage ni LocalStorage n'ont intégré cette fonctionnalité, nous devons donc l'implémenter manuellement. Nous le ferons en enregistrant toujours l'horodatage du temps stocké et en l'utilisant pour comparer les éventuels coups sûrs de cache.
Mais à quoi cela ressemblera-t-il avant de faire cela? Par exemple:
fetch('https://httpbin.org/get') .then(r => r.json()) .then(info => { sessionStorage.setItem('information', JSON.stringify(info)); }); // 需要延迟以确保fetch已完成 setTimeout(() => { let info = JSON.parse(sessionStorage.getItem('information')); console.log('您的来源是 ' + info.origin); }, 3000);
La nouvelle chose clé que nous ajouterons est que chaque fois que nous enregistrons les données de réponse, nous enregistrerons également quand quand le stockerons. Mais veuillez noter que maintenant nous pouvons également passer à un stockage plus fiable de LocalStorage au lieu de SessionStorage. Notre code expiré personnalisé garantira que nous n'obtenons pas des coups de cache très périmés dans le storage local persistant. donc c'est notre solution de travail ultime:
fetch('https://httpbin.org/get') .then(r => r.json()) .then(issues => { console.log('您的来源是 ' + info.origin); });
La réalisation du futur - mieux, plus fantaisie, plus cool
. Il mesure d'autres choses, mais conclut essentiellement que le storage local est très rapide et que l'échauffement du cache disque est rare. Alors, comment améliorer davantage nos solutions?
Notre implémentation ici ne cache pas le contenu non texte (comme les images), mais il n'y a aucune raison de ne pas se cacher. Nous avons besoin de plus de code. En particulier, nous voulons peut-être stocker plus d'informations sur le blob. Chaque réponse est essentiellement un blob. Pour le texte et JSON, ce n'est qu'un éventail de chaînes. Le type et la taille n'ont pas d'importance, car vous pouvez déduire de la chaîne elle-même. Pour le contenu binaire, le BLOB doit être converti en ArrayBuffer.
Pour les gens curieux, pour afficher les extensions d'implémentation qui prennent en charge les images, veuillez vérifier ce codep: [https://www.php.cn/link/946af35555203afdb63e571b873e419f6].
Une autre amélioration potentielle consiste à échanger l'espace contre la vitesse en hachant chaque URL (nous utilisons comme clés) pour la rendre plus petite. Dans l'exemple ci-dessus, nous n'utilisons que des URL très petites et concises (par exemple httpbin.org/get), mais si vous avez de très longues URL, il y a beaucoup de contenu de chaîne de requête, et il y a beaucoup de ces URL , alors ils s'ajouteront beaucoup.
La solution à ce problème consiste à utiliser cet algorithme intelligent, qui est considéré comme sûr et rapide:
let origin = null; fetch('https://httpbin.org/get') .then(r => r.json()) .then(information => { origin = information.origin; // 您的客户端IP }); // 需要延迟以确保fetch已完成 setTimeout(() => { console.log('您的来源是 ' + origin); }, 3000);
Si vous aimez cela, consultez ce codePen: [https://www.php.cn/link/946af355203afdb63e571b873e419f6]. Si vous vérifiez le stockage dans la console Web, vous verrez une clé similaire à 557027443.
Vous avez maintenant une solution de travail que vous pouvez ajouter à votre application Web, où vous utilisez probablement l'API Web et vous savez que les réponses peuvent être bien mises en cache pour vos utilisateurs.
La dernière chose pourrait être une extension naturelle de ce prototype, c'est-à-dire pour le déplacer au-delà de l'article, dans un projet réel et spécifique avec des tests et des lectures et le publier sur NPM - mais cela doit être dit plus tard!
Les demandes AJAX sont essentielles à la mise en cache pour améliorer les performances de votre application Web. Il permet au navigateur de stocker une copie de la réponse du serveur afin qu'il n'ait pas à refaire la même demande. Cela réduit la charge sur le serveur et accélère le temps de chargement de la page Web, offrant ainsi une meilleure expérience utilisateur.
API Fetch fournit un moyen puissant et flexible de faire des demandes HTTP. Il comprend un mécanisme de mise en cache intégré qui vous permet de spécifier comment les demandes doivent interagir avec le cache. Vous pouvez définir le mode de cache sur "par défaut", "sans magasin", "rechargement", "sans cache", "force-cache" ou "uniquement si-cache", chacun avec différents niveaux de contrôle du cache.
L'API Fetch fournit plusieurs modes de cache. "par défaut" suit les règles de mise en cache HTTP standard. "Pas de magasin" contourne complètement le cache. "Recharger" ignore toutes les données mises en cache et envoie de nouvelles demandes. "No-Cache" utilise le serveur pour vérifier les données avant d'utiliser la version mise en cache. "Force-Cache" utilise des données mises en cache quelle que soit sa fraîcheur. "uniquement IF-cache" ne l'utilise que lorsque les données de cache sont disponibles, sinon elles échouent.
Vous pouvez implémenter le cache dans les demandes AJAX en définissant l'attribut de cache dans les paramètres AJAX. S'il est défini sur true, cela permettra au navigateur de mettre en cache la réponse. Alternativement, vous pouvez utiliser les options de cache de l'API Fetch pour mieux contrôler le comportement du cache.
Pour empêcher la mise en cache dans les demandes AJAX, vous pouvez définir la propriété Cache dans les paramètres AJAX sur FALSE. Cela obligera le navigateur à ne pas stocker sa réponse dans son cache. Alternativement, vous pouvez utiliser l'option de mise en cache "sans magasin" de l'API Fetch pour contourner entièrement le cache.
Bien que les API AJAX et les API fetch fournissent des mécanismes de mise en cache, l'API Fetch offre une plus grande flexibilité et contrôle. La propriété Cache d'Ajax est une simple valeur booléenne qui permet ou ne permet pas le cache. D'un autre côté, l'option de cache de l'API Fetch vous permet de spécifier comment les demandes doivent interagir avec le cache, vous donnant un contrôle plus granulaire.
Le cache peut considérablement améliorer les performances des applications Web. En stockant une copie de la réponse du serveur, le navigateur n'a pas à refaire la même demande. Cela réduit la charge sur le serveur et accélère le temps de chargement de la page Web. Cependant, le cache doit être géré correctement pour garantir que vos utilisateurs voient le dernier contenu.
Oui, vous pouvez contrôler le comportement de cache d'une seule demande AJAX en définissant l'attribut de cache dans les paramètres AJAX pour chaque demande. Cela vous permet de spécifier si le navigateur doit mettre en cache la réponse.
Effacer le cache demandé par AJAX peut être effectué en définissant la propriété de cache sur FALSE dans les paramètres AJAX. Cela obligera le navigateur à ne pas stocker sa réponse dans son cache. Alternativement, vous pouvez utiliser l'option de cache "Recharger" de l'API Fetch pour ignorer toutes les données mises en cache et envoyer de nouvelles demandes.
Certaines meilleures pratiques pour la mise en cache des demandes AJAX incluent: Comprendre différents modes de cache et quand les utiliser, gérer correctement le cache pour garantir que les utilisateurs voient le dernier contenu et l'utilisation des options de cache de l'API Fetch pour un meilleur contrôle sur les caches. Lors de la décision d'une stratégie de mise en cache, la nature des données et de l'expérience utilisateur doit également être prise en compte.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!