111 votes

Vitesse/coût du stockage local

Quelle est la vitesse de recherche d'une valeur dans localStorage avec Javascript ?

Quelqu'un a-t-il des liens vers des tests de performance qui indiquent si cela vaut la peine ou non de mettre en cache les données dans un objet JavaScript ? Ou bien le navigateur met-il déjà en cache les valeurs auxquelles on accède à partir de localStorage de toute façon ?

Je suis particulièrement intéressé par les implémentations Firefox et Chrome de localStorage.

69voto

Lukas Liesis Points 564

Je viens de réaliser un petit benchmark. Ce que je prévois de faire, c'est de récupérer assez souvent des données de localStorage et je me demandais si cela allait bloquer. Alors que l'opération localStorage.getItem est synchronisée, cela peut sembler effrayant mais est-ce bien le cas ?

  • 1er test pour appeler 1 million de fois localStorage pour obtenir un élément qui existe.
  • 2ème test pour appeler 1 million de fois localStorage pour obtenir un élément qui n'existe PAS.

Résultats :

"Article trouvé : 0.0007991071428571318ms par appel"

"Elément non trouvé : 0.0006365004639793477ms par appel"

En bref, il suffit de l'utiliser. Cela ne prend pas de temps. 0.0007 de 1 milliseconde.

https://jsbin.com/resuziqefa/edit?js,console

 let results = [];
 let sum = 0;
 localStorage.setItem('foo', 'foo bar baz foo bar baz foo bar baz foo');

 for (let i = 0; i < 1000000; i++) {
   let a = performance.now();
   localStorage.getItem('foo');
   let result = performance.now() - a;
   sum += result;
   results.push(result);
 }

 console.log(`Item found: ${sum / results.length}ms per call`);

 results = [];
 sum = 0;
 for (let i = 0; i < 1000000; i++) {
   let a = performance.now();
   localStorage.getItem('bar');
   let result = performance.now() - a;
   sum += result;
   results.push(result);
 }

 console.log(`Item not found: ${sum / results.length}ms per call`);

9 votes

Vous avez besoin d'un point de référence, comment se situe-t-il par rapport à l'accès variable ?

11 votes

@Kugel cela n'a pas été fait pour comparer mais pour vérifier si le magasin localhost fonctionne suffisamment vite pour ne pas avoir, ou au moins pas, d'impact sur les performances globales. Je me demande comment le test devrait être écrit pour avoir une vraie comparaison sur les choses que vous voulez comparer et c'est certainement hors de la portée de cette question. Lorsque les actions se produisent en 0,0007ms, même ce test n'est probablement pas assez précis et ne couvre pas les aspects du fonctionnement du CPU et du moteur JS lui-même. Mon intérêt était de vérifier si localhost est "rapide" en général.

1 votes

Avez-vous testé cela avec de gros objets au lieu d'une simple chaîne de caractères ?

55voto

Pour ce que cela vaut, voici une test jsperf .

L'utilisation de référence de localStorage es sensiblement plus lent que l'accès d'un propriétés des objets réguliers dans FF7 et IE9. Bien entendu, il ne s'agit que d'un micro-benchmark, et ne reflète pas nécessairement l'utilisation ou les performances réelles. ...

Echantillon tiré de mon exécution FF 7 pour montrer ce que signifie "significativement plus lent", en ops/seconde :

            native     local-storage    notes
small set   374,397    13,657           10 distinct items
large set   2,256      68               100 distinct items
read-bias   10,266     342              1 write, 10 reads, 10 distinct items

Il y a aussi des restrictions sur ce qui peut être mis dans le LocalStorage . YMMV.

8 votes

Mais les objets ordinaires ne sont pas persistants. C'est comme comparer l'accès aux variables avec le stockage SQL. Ils ont des objectifs distincts et le premier est toujours beaucoup plus rapide que le second.

3 votes

@cchamberlain Il est toujours important de le savoir, par exemple lorsqu'on se demande s'il faut mettre en cache les données fréquemment utilisées dans la page (et éventuellement gérer la cohérence entre plusieurs onglets/fenêtres) ou s'il faut toujours les récupérer à partir de localStorage . Je suis actuellement confronté à cette décision pour un jeton de rafraîchissement OAuth et d'autres états persistants de l'application. Par coïncidence, un autre Lukas a déjà discuté de cette question en dessous de votre réponse.

33voto

Cole Chamberlain Points 1263

Des pommes pour des pommes

Il n'y a pas grand intérêt à comparer localStorage au stockage d'objets, les deux ont des objectifs différents en JavaScript. Il est probable que vous n'aurez besoin de toucher qu'aux éléments suivants localStorage quelques fois dans votre application et le reste du travail sera fait en mémoire.

Stockage local ou cookies

Une meilleure comparaison avec localStorage serait celle de son homologue classique, document.cookie . Les deux sites localStorage y document.cookie L'objectif principal de l'outil est de faire persister une valeur à travers les rafraîchissements du navigateur.

J'ai mis en place un exemple sur codsandbox.io

  • localStorage est deux ordres de grandeur plus rapide que document.cookie .
  • Object est un ordre de grandeur plus rapide que localStorage (non pertinent mais ajouté pour référence).

localStorage est de loin le mécanisme le plus rapide pour faire persister des valeurs lors d'un rafraîchissement du navigateur.

localstoragevcookies

Notez que j'ai précompilé les getters regex des cookies afin de les rendre aussi rapides que possible et que j'ai utilisé l'API de performance du navigateur pour des mesures précises. Tous les tests font un set d'une clé unique suivi d'un get de la même clé.

8 votes

Ce n'est pas le sujet et cela ne répond pas à la question. Peut-être que je veux décider si je dois garder un cache de ma variable partagée dans le stockage régulier (et la mettre à jour périodiquement) ou simplement la laisser dans localStorage et la vérifier fréquemment ? C'est l'objet de la question, et ceci n'y répond pas.

3 votes

Définir le "stockage régulier". Le fait de placer une valeur dans une variable globale n'a pas grand-chose à voir avec le fait de localStorage du point de vue des cas d'utilisation. La lecture des données de localStorage le fait passer du disque à la mémoire, de sorte que vous comparez une chose, A , à A + B . L'une est destinée à une utilisation temporaire en mémoire et l'autre à la persistance sur disque. On n'achète pas la mémoire vive et les disques durs dans le même rayon. Cette question jette un mauvais éclairage sur localStorage et ce n'est même pas une comparaison avec son homologue classique, le biscuit.

1 votes

Si vous cherchez une façon de stocker un objet et que vous essayez de le faire avec le stockage local, je parie que la plupart du temps sera consacré à déplacer l'objet vers la chaîne et vice-versa. par exemple, la façon la plus populaire serait JSON stringify qui est une opération assez lente.

17voto

AlexTes Points 197

J'apprécie les efforts des réponses précédentes mais j'ai trouvé que les repères manquaient. Voici un meilleur micro-benchmark, notez qu'il s'agit toujours d'un micro-benchmark. Je préfère toujours mesurer les goulots d'étranglement réels des performances plutôt que de faire une optimisation prématurée des performances.

Les tests de référence portent sur la lecture et l'écriture d'une valeur unique, d'une liste de cent objets et d'une liste de dix mille objets depuis et vers localStorage.

TL;DR :

single read: 0.0004ms, write: 0.0114ms
small list read: 0.0325ms, write: 0.0498ms
large list read: 3.1787ms, write: 3.3190ms

Fonctionne sur un Intel Core i7 Quad-Core de 3,1 GHz. Chrome 79.

read local storage - single x 2,439,715 ops/sec ±0.91% (62 runs sampled)
read local storage - small x 30,742 ops/sec ±0.78% (62 runs sampled)
read local storage - large x 315 ops/sec ±1.30% (60 runs sampled)
write local storage - single x 88,032 ops/sec ±4.25% (33 runs sampled)
write local storage - small x 20,079 ops/sec ±1.89% (59 runs sampled)
write local storage - large x 301 ops/sec ±1.09% (60 runs sampled)

Test: read local storage - single
mean: 0.0004098839352502669ms
margin of error: ±0.000003731514453196282ms
devation: ±0.00001499080315635531ms

Test: read local storage - small
mean: 0.03252840093744983ms
margin of error: ±0.0002551322114660716ms
devation: ±0.001024955633672395ms

Test: read local storage - large
mean: 3.1786666666666674ms
margin of error: ±0.041479799689699ms
devation: ±0.16392915653288143ms

Test: write local storage - single
mean: 0.011359496605398242ms
margin of error: ±0.00048286808926899016ms
devation: ±0.0014152377493978731ms

Test: write local storage - small
mean: 0.04980309857651518ms
margin of error: ±0.0009408982120607311ms
devation: ±0.0036873348473201325ms

Test: write local storage - large
mean: 3.31899154589372ms
margin of error: ±0.03605551145015122ms
devation: ±0.14249224018921072ms

Voici un extrait pour l'exécuter vous-même si vous le souhaitez.

<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.15/lodash.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/benchmark/2.1.4/benchmark.min.js"></script>
<script>
  const suite = new Benchmark.Suite();

  const genNum = () => Math.floor(Math.random() * 1000000);

  const genObj = () => ({
    target: String(genNum()),
    swap: String(genNum()),
    price: genNum()
  });

  const printStats = test =>
    console.log(
      `Test: ${test.name}
mean: ${test.stats.mean * 1000}ms
margin of error: ±${test.stats.moe * 1000}ms
devation: ±${test.stats.deviation * 1000}ms`
    );

  const singleNum = String(genNum());
  const smallList = _.range(100).map(genObj);
  const largeList = _.range(10000).map(genObj);

  const singleKey = "single-key";
  const smallKey = "small-key";
  const largeKey = "large-key";

  localStorage.setItem(singleKey, singleNum);
  localStorage.setItem(smallKey, JSON.stringify(smallList));
  localStorage.setItem(largeKey, JSON.stringify(largeList));

  suite
    .add("read local storage - single", function() {
      const readData = localStorage.getItem(singleKey);
    })
    .add("read local storage - small", function() {
      const readData = JSON.parse(localStorage.getItem(smallKey));
    })
    .add("read local storage - large", function() {
      const readData = JSON.parse(localStorage.getItem(largeKey));
    })
    .add("write local storage - single", function() {
      localStorage.setItem("single_write_key", singleNum);
    })
    .add("write local storage - small", function() {
      localStorage.setItem("small_write_key", JSON.stringify(smallList));
    })
    .add("write local storage - large", function() {
      localStorage.setItem("large_write_key", JSON.stringify(largeList));
    })
    .on("cycle", function(event) {
      console.log(String(event.target));
    })
    .on("complete", function() {
      this.forEach(printStats);
    })
    .run({ async: true });
</script>

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X