Maison  >  Article  >  interface Web  >  Découvrez les différents types de stockage dans les navigateurs

Découvrez les différents types de stockage dans les navigateurs

青灯夜游
青灯夜游avant
2020-11-24 17:52:003902parcourir

Découvrez les différents types de stockage dans les navigateurs

Dans le développement backend, le stockage est une partie courante du travail. Les données des applications sont stockées dans des bases de données, les fichiers sont stockés dans le stockage objet, les données transitoires sont stockées dans des caches... il existe des possibilités apparemment infinies pour stocker tout type de données. Cependant, le stockage des données ne se limite pas au backend , le frontend (navigateur) dispose également de nombreuses options pour stocker les données. Nous pouvons améliorer les performances de nos applications en tirant parti de cette méthode de stockage, enregistrer les préférences de l'utilisateur et maintenir l'état des applications sur plusieurs sessions et même sur différents ordinateurs.

Dans cet article nous passerons en revue les différentes possibilités de stockage de données dans le navigateur. Nous aborderons trois cas d'utilisation pour chaque approche afin de comprendre ses avantages et ses inconvénients. En fin de compte, vous serez en mesure de décider quel stockage convient le mieux à votre cas d'utilisation.

Commençons ! L'

API localStorage

localStorage est l'une des options de stockage les plus populaires dans les navigateurs et le premier choix de nombreux développeurs. Les données sont stockées sur plusieurs sessions, jamais partagées avec le serveur et disponibles pour toutes les pages sous le même protocole et domaine. La limite de stockage est d'environ 5 Mo.

Étonnamment, l'équipe de Google Chrome ne recommande pas d'utiliser cette option car elle bloque le thread principal et rend les Web Workers et Service Workers inaccessibles. Ils ont lancé une expérience : KV Storage, comme une meilleure version, mais ce n'était qu'une expérience et il ne semble pas encore y avoir de progrès.

localStorage API est disponible en tant que window.localStorage et ne peut contenir que des chaînes UTF-16. Avant de sauvegarder les données sur localStorage, nous devons nous assurer qu'elles sont converties en chaîne. Les trois fonctions principales sont :

  • setItem('key', 'value')
  • getItem('key')
  • removeItem('key')

Ils tous sont synchrones donc simples à utiliser, mais ils bloquent le thread principal.

Il convient de mentionner que localStorage a un jumeau nommé sessionStorage. La seule différence est que les données stockées dans sessionStorage ne persisteront que pour la session en cours, mais l'API est la même.

C'est si simple que je crois que tout le monde l'a utilisé.

API IndexedDB

IndexedDB est une solution de stockage moderne dans le navigateur. Il peut stocker de grandes quantités de données structurées, même des fichiers et des blobs. Comme toute base de données, IndexedDB indexe les données pour exécuter des requêtes efficacement. Utiliser IndexedDB est plus compliqué, nous devons créer une base de données, des tables et utiliser des transactions.

IndexedDB nécessite plus de code que localStorage. Dans l'exemple, j'ai utilisé l'API native avec un wrapper Promise, mais je recommande fortement d'utiliser une bibliothèque tierce pour vous aider. Ce que je recommande, c'est localForage, car il utilise la même API localStorage, mais l'implémentation est progressivement améliorée, c'est-à-dire que si votre navigateur prend en charge IndexedDB, il l'utilisera s'il ne la prend pas en charge, il reviendra à . localStorage

Codons et passons à notre exemple de préférences utilisateur !

<input>
<label>Dark theme</label><br>
rrreeEffect

Découvrez les différents types de stockage dans les navigateurs

est un wrapper Promise que nous utilisons au lieu d'utiliser l'API basée sur les événements de bas niveau. La première chose à noter est que chaque accès à la base de données est asynchrone, ce qui signifie que nous ne bloquons pas le thread principal, ce qui est un avantage majeur par rapport à idb. localStorage

Nous devons ouvrir une connexion à la base de données afin qu'elle puisse être utilisée en lecture et en écriture dans toute l'application. Nous donnons à la base de données un nom

, une version de schéma my-db et une fonction de mise à jour pour appliquer les modifications entre les versions, un peu comme les migrations de bases de données. Notre architecture de base de données est simple : un seul magasin d'objets 1. Le magasin d'objets est équivalent à une table SQL, pour écrire ou lire dans la base de données, vous devez utiliser des transactions, ce qui est la partie fastidieuse de l'utilisation d'IndexedDB. Jetez un œil aux nouvelles fonctionnalités preferences et save dans la démo. load

Il ne fait aucun doute qu'IndexedDB a plus de frais généraux et une courbe d'apprentissage plus abrupte que

. Pour le cas clé-valeur, il pourrait être plus judicieux d'utiliser localStorage ou une bibliothèque tierce, ce qui nous aidera à être plus efficaces. localStorage

let db;

function toggle(on) {
  if (on) {
    document.documentElement.classList.add('dark'); 
  } else {
    document.documentElement.classList.remove('dark');    
  }
}

async function save(on) {
  const tx = db.transaction('preferences', 'readwrite');
  const store = tx.objectStore('preferences');
  store.put({key: 'darkTheme', value: on});
  return tx.complete;
}

async function load() {
  const tx = db.transaction('preferences', 'readonly');
  const store = tx.objectStore('preferences');
  const data = await store.get('darkTheme');
  return data && data.value;
}

async function onChange(checkbox) {
  const value = checkbox.checked;
  toggle(value);
  await save(value);
}

function openDatabase() {
  return idb.openDB('my-db', 1, {
    upgrade(db) {
      db.createObjectStore('preferences', {keyPath: 'key'});
    },
  });
}

openDatabase()
  .then((_db) => {
    db = _db;
    return load();
  })
  .then((initialValue) => {
    toggle(initialValue);
    document.querySelector('#darkTheme').checked = initialValue;
  });
rrreeEffet

Découvrez les différents types de stockage dans les navigateurs

Vous pouvez stocker des centaines de mégaoctets ou plus dans cette base de données. Vous pouvez stocker tous vos Pokémon dans IndexedDB, les mettre hors ligne et même les indexer ! Il s'agit certainement d'une option pour stocker les données d'application.

J'ai sauté l'implémentation du troisième exemple car IndexedDB ne fait aucune différence dans ce cas par rapport à

. Même avec IndexedDB, les utilisateurs ne partageront toujours pas la page sélectionnée avec d'autres personnes ni ne la mettront en favoris pour une utilisation ultérieure. Aucun d’entre eux n’est adapté à ce cas d’utilisation. localStorage

Cookies

使用cookies是一种独特的存储方式,这是唯一的与服务器共享的存储方式。Cookies作为每次请求的一部分被发送。它可以是当用户浏览我们的应用程序中的页面或当用户发送Ajax请求时。这样我们就可以在客户端和服务器之间建立一个共享状态,也可以在不同子域的多个应用程序之间共享状态。本文中介绍的其他存储选项无法实现。需要注意的是:每个请求都会发送 cookie,这意味着我们必须保持 cookie 较小,以保持适当的请求大小。

Cookies的最常见用途是身份验证,这不在本文的讨论范围之内。就像 localStorage 一样,cookie只能存储字符串。这些cookie被连接成一个以分号分隔的字符串,并在请求的cookie头中发送。你可以为每个cookie设置很多属性,比如过期、允许的域名、允许的页面等等。

在例子中,我展示了如何通过客户端来操作cookie,但也可以在你的服务器端应用程序中改变它们。

<input>
<label>Dark theme</label>
function getCookie(cname) {
  const name = cname + '=';
  const decoded = decodeURIComponent(document.cookie);
  const split = decoded.split(';');
  const relevantCookie = split.find((cookie) => cookie.indexOf(`${cname}=`) === 0);
  if (relevantCookie) {
    return relevantCookie.split('=')[1];
  }
  return null;
}

function toggle(on) {
  if (on) {
    document.documentElement.classList.add('dark'); 
  } else {
    document.documentElement.classList.remove('dark');    
  }
}

function save(on) {
  document.cookie = `dark_theme=${on.toString()}; max-age=31536000; SameSite=None; Secure`;
}

function load() {
  return getCookie('dark_theme') === 'true';
}

function onChange(checkbox) {
  const value = checkbox.checked;
  toggle(value);
  save(value);
}

const initialValue = load();
toggle(initialValue);
document.querySelector('#darkTheme').checked = initialValue;

效果还是跟前面一样

Découvrez les différents types de stockage dans les navigateurs

将用户的喜好保存在cookie中,如果服务器能够以某种方式利用它,就可以很好地满足用户的需求。例如,在主题用例中,服务器可以交付相关的CSS文件,并减少潜在的捆绑大小(在我们进行服务器端渲染的情况下)。另一个用例可能是在没有数据库的情况下,在多个子域应用之间共享这些偏好。

用JavaScript读写cookie并不像您想象的那么简单。要保存新的cookie,您需要设置 document.cookie ——在上面的示例中查看 save 函数。我设置了 dark_theme cookie,并给它添加了一个 max-age 属性,以确保它在关闭标签时不会过期。另外,我添加 SameSiteSecure 属性。这些都是必要的,因为CodePen使用iframe来运行这些例子,但在大多数情况下你并不需要它们。读取一个cookie需要解析cookie字符串。

Cookie字符串如下所示:

key1=value1;key2=value2;key3=value3

因此,首先,我们必须用分号分隔字符串。现在,我们有一个形式为 key1=value1 的Cookie数组,所以我们需要在数组中找到正确的元素。最后,我们将等号分开并获得新数组中的最后一个元素。有点繁琐,但一旦你实现了 getCookie 函数(或从我的例子中复制它:P),你就可以忘记它。

将应用程序数据保存在cookie中可能是个坏主意!它将大大增加请求的大小,并降低应用程序性能。此外,服务器无法从这些信息中获益,因为它是数据库中已有信息的陈旧版本。如果你使用cookies,请确保它们很小。

分页示例也不适合cookie,就像 localStorageIndexedDB 一样。当前页面是我们想要与他人共享的临时状态,这些方法都无法实现它。

URL storage

URL本身并不是存储设备,但它是创建可共享状态的好方法。实际上,这意味着将查询参数添加到当前URL中,这些参数可用于重新创建当前状态。最好的例子是搜索查询和过滤器。如果我们在CSS-Tricks上搜索术语flexbox,则URL将更新为https://css-tricks.com/?s=fle...。看看我们使用URL后,分享搜索查询有多简单?另一个好处是,你只需点击刷新按钮,就可以获得更新的查询结果,甚至可以将其收藏。

我们只能在URL中保存字符串,它的最大长度是有限的,所以我们没有那么多的空间。我们将不得不保持我们的状态小,没有人喜欢又长又吓人的网址。

同样,CodePen使用iframe运行示例,因此您看不到URL实际更改。不用担心,因为所有的碎片都在那里,所以你可以在任何你想要的地方使用它。

<input>
<label>Dark theme</label>
function toggle(on) {
  if (on) {
    document.documentElement.classList.add('dark'); 
  } else {
    document.documentElement.classList.remove('dark');    
  }
}

function save(on) {
  const params = new URLSearchParams(window.location.search);
  params.set('dark_theme', on.toString());
  history.pushState(null, null, `?${params.toString()}`);
}

function load() {
  const params = new URLSearchParams(window.location.search);
  return params.get('dark_theme') === 'true';
}

function onChange(checkbox) {
  const value = checkbox.checked;
  toggle(value);
  save(value);
}

const initialValue = load();
toggle(initialValue);
document.querySelector('#darkTheme').checked = initialValue;

效果还是一样

Découvrez les différents types de stockage dans les navigateurs

我们可以通过 window.location.search 访问查询字符串,幸运的是,可以使用 URLSearchParams 类对其进行解析,无需再应用任何复杂的字符串解析。当我们想读取当前值时,可以使用 get 函数,当我们想写时,可以使用 set。仅设置值是不够的,我们还需要更新URL。这可以使用 history.pushStatehistory.replaceState 来完成,取决于我们想要完成的行为。

我不建议将用户的偏好保存在URL中,因为我们必须将这个状态添加到用户访问的每一个URL中,而且我们无法保证;例如,如果用户点击了谷歌搜索的链接。

就像Cookie一样,由于空间太小,我们无法在URL中保存应用程序数据。而且即使我们真的设法存储它,网址也会很长,而且不吸引人点击。可能看起来像是钓鱼攻击的一种。

<p>Select page:</p>
<p>
  <button>0</button>
  <button>1</button>
  <button>3</button>
  <button>4</button>
  <button>5</button>
</p>
async function loadPokemons(page) {
  const res = await fetch(`https://pokeapi.co/api/v2/pokemon?limit=10&offset=${page * 10}`);
  const data = await res.json();
  return data.results;
}

function appendPokemon(pokemon) {
  const node = document.createElement('li');
  const textnode = document.createTextNode(pokemon.name);
  node.appendChild(textnode);
  document.querySelector('#list').appendChild(node);
}

function clearList() {
  const list = document.querySelector('#list');
  while (list.firstChild) {
    list.removeChild(list.lastChild);
  }
}

function savePage(page) {
  const params = new URLSearchParams(window.location.search);
  params.set('page', page.toString());
  history.pushState(null, null, `?${params.toString()}`);
}

function loadPage() {
  const params = new URLSearchParams(window.location.search);
  if (params.has('page')) {
    return parseInt(params.get('page'));
  }
  return 0;
}

async function updatePage(page) {
  clearList();
  savePage(page);
  const pokemons = await loadPokemons(page);
  pokemons.forEach(appendPokemon);
}

const page = loadPage();
updatePage(page);

效果

Découvrez les différents types de stockage dans les navigateurs

就像我们的分页例子一样,临时应用状态是最适合URL查询字符串的。同样,你无法看到URL的变化,但每次点击一个页面时,URL都会以 ?page=x 查询参数更新。当网页加载时,它会查找这个查询参数,并相应地获取正确的页面。现在,我们可以把这个网址分享给我们的朋友,让他们可以享受我们最喜欢的神奇宝贝。

Cache API

Cache API是网络级的存储,它用于缓存网络请求及其响应。Cache API非常适合service worker,service worker可以拦截每一个网络请求,使用 Cache API 它可以轻松地缓存这两个请求。service worker也可以将现有的缓存项作为网络响应返回,而不是从服务器上获取。这样,您可以减少网络负载时间,并使你的应用程序即使处于脱机状态也能正常工作。最初,它是为service worker创建的,但在现代浏览器中,Cache API也可以在窗口、iframe和worker上下文中使用。这是一个非常强大的API,可以极大地改善应用的用户体验。

就像IndexedDB一样,Cache API的存储不受限制,您可以存储数百兆字节,如果需要甚至可以存储更多。API是异步的,所以它不会阻塞你的主线程,而且它可以通过全局属性 caches 来访问。

Browser extension

如果你建立一个浏览器扩展,你有另一个选择来存储你的数据,我在进行扩展程序daily.dev时发现了它。如果你使用Mozilla的polyfill,它可以通过 chrome.storagebrowser.storage 获得。确保在你的清单中申请一个存储权限以获得访问权。

有两种类型的存储选项:local和sync。local存储是不言而喻的,它的意思是不共享,保存在本地。sync存储是作为谷歌账户的一部分同步的,你在任何地方用同一个账户安装扩展,这个存储都会被同步。两者都有相同的API,所以如果需要的话,来回切换超级容易。它是异步存储,因此不会像 localStorage 这样阻塞主线程。不幸的是,我不能为这个存储选项创建一个演示,因为它需要一个浏览器扩展,但它的使用非常简单,几乎和 localStorage 一样。有关确切实现的更多信息,请参阅Chrome文档。

结束

浏览器有许多选项可用于存储数据。根据Chrome团队的建议,我们的首选存储应该是IndexedDB,它是异步存储,有足够的空间来存储我们想要的任何东西。不鼓励使用 localStorage,但它比 IndexedDB 更易于使用。Cookies是与服务器共享客户端状态的一种好方法,但通常用于身份验证。

如果你想创建具有可共享状态的页面,如搜索页面,请使用URL的查询字符串来存储这些信息。最后,如果你建立一个扩展,一定要阅读关于 chrome.storage

更多编程相关知识,请访问:编程视频!!

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!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer