Heim  >  Artikel  >  Web-Frontend  >  Erfahren Sie mehr über die verschiedenen Speichertypen in Browsern

Erfahren Sie mehr über die verschiedenen Speichertypen in Browsern

青灯夜游
青灯夜游nach vorne
2020-11-24 17:52:003991Durchsuche

Erfahren Sie mehr über die verschiedenen Speichertypen in Browsern

In der Backend-Entwicklung ist die Speicherung ein häufiger Bestandteil der Arbeit. Anwendungsdaten werden in Datenbanken gespeichert, Dateien werden im Objektspeicher gespeichert, transiente Daten werden in Caches gespeichert … es gibt scheinbar endlose Möglichkeiten, jede Art von Daten zu speichern. Allerdings beschränkt sich die Datenspeicherung nicht nur auf das Backend , auch das Frontend (Browser) bietet viele Möglichkeiten zur Datenspeicherung. Wir können die Leistung unserer Anwendungen verbessern, indem wir diese Speichermethode nutzen, Benutzereinstellungen speichern und den Anwendungsstatus über mehrere Sitzungen und sogar verschiedene Computer hinweg beibehalten.

In diesem Artikel gehen wir auf die verschiedenen Möglichkeiten der Datenspeicherung im Browser ein. Wir werden drei Anwendungsfälle für jeden Ansatz behandeln, um seine Vor- und Nachteile in den Griff zu bekommen. Am Ende können Sie entscheiden, welcher Speicher für Ihren Anwendungsfall am besten geeignet ist.

Lass uns anfangen!

localStorage API

localStorage ist eine der beliebtesten Speicheroptionen in Browsern und die erste Wahl für viele Entwickler. Daten werden sitzungsübergreifend gespeichert, niemals mit dem Server geteilt und sind für alle Seiten unter demselben Protokoll und derselben Domäne verfügbar. Das Speicherlimit beträgt ~5 MB. localStorage 是浏览器中最受欢迎的存储选项之一,也是许多开发人员的首选。数据跨会话存储,从不与服务器共享,并且可用于同一协议和域下的所有页面。存储空间限制为〜5MB。

令人惊讶的是,谷歌Chrome团队并不建议使用这个选项,因为它屏蔽了主线程,而且web workers和service workers无法访问。他们推出了一个实验:KV Storage,作为一个更好的版本,但这只是一个试验,似乎还没有任何进展。

localStorage API 可作为 window.localStorage 使用,并且只能保存UTF-16字符串。在将数据保存到 localStorage 之前,我们必须确保将其转换为字符串。主要的三个功能是:

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

它们都是同步的,因此使用起来很简单,但是它们会阻塞主线程。

值得一提的是,localStorage 有一个称为 sessionStorage 的双胞胎。唯一的区别是,存储在 sessionStorage 中的数据将仅持续当前会话,但API相同。

这个太简单了,相信大家都用过。

IndexedDB API

IndexedDB是浏览器中的现代存储解决方案。它可以存储大量的结构化数据,甚至文件和Blob。和每一个数据库一样,IndexedDB对数据进行索引,以便高效地运行查询。使用IndexedDB比较复杂,我们必须创建一个数据库,表,并使用事务。

localStorage 相比,IndexedDB需要更多代码。在例子中,我使用了原生API与Promise包装器,但我强烈建议使用第三方库来帮助你。我推荐的是localForage,因为它使用了同样的 localStorage API,但实现方式是逐步增强的,也就是说,如果你的浏览器支持IndexedDB,就会使用它;如果不支持,就会退回到 localStorage

让我们来编写代码,前往我们的用户偏好示例吧!

<input>
<label>Dark theme</label><br>
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;
  });

效果

Erfahren Sie mehr über die verschiedenen Speichertypen in Browsern

idb 是我们使用的Promise包装器,而不是使用基于事件的低级API。首先要注意的是,对数据库的每次访问都是异步的,这意味着我们不会阻塞主线程,与 localStorage 相比,这是一个主要优势。

我们需要打开与数据库的连接,以便在整个应用程序中都可以使用它进行读写。我们给数据库起一个名字 my-db,一个模式版本 1,以及一个更新函数,以在版本之间应用更改,这与数据库迁移非常相似。我们的数据库架构很简单:只有一个object store preferences。object store 等效于SQL表,要写入或读取数据库,必须使用事务,这是使用IndexedDB的乏味部分。看一下演示中新的 saveload 功能。

毫无疑问,IndexedDB具有更多的开销,并且与 localStorage 相比,学习曲线更陡峭。对于键值的情况,使用 localStorage 或第三方库可能更有意义,它们将帮助我们提高效率。

<p>loading...</p>
let db;

async function loadPokemons() {
  const res = await fetch('https://pokeapi.co/api/v2/pokemon?limit=10');
  const data = await res.json();
  return data.results;
}

function removeLoading() {
  const elem = document.querySelector('#loading');
  if (elem) {
    elem.parentNode.removeChild(elem); 
  }
}

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 saveToCache(pokemons) {
  const tx = db.transaction('pokemons', 'readwrite');
  const store = tx.objectStore('pokemons');
  pokemons.forEach(pokemon => store.put(pokemon));
  return tx.complete;
}

function loadFromCache() {
  const tx = db.transaction('pokemons', 'readonly');
  const store = tx.objectStore('pokemons');
  return store.getAll();
}

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

openDatabase()
  .then((_db) => {
    db = _db;
    return loadFromCache();
  })
  .then((cachedPokemons) => {
    if (cachedPokemons) {
      removeLoading();
      cachedPokemons.forEach(appendPokemon);
      console.log('loaded from cache!');
    }
    return loadPokemons();
  })
  .then((pokemons) => {
    removeLoading();
    saveToCache(pokemons);
    clearList();
    pokemons.forEach(appendPokemon);
    console.log('loaded from network!');
  });

效果

Erfahren Sie mehr über die verschiedenen Speichertypen in Browsern

你可以在此数据库中存储数百兆甚至更多。您可以将所有Pokémon存储在IndexedDB中,并使其脱机甚至建立索引!这绝对是用于存储应用程序数据的一种选择。

我跳过了第三个示例的实现,因为与 localStorage

Überraschenderweise empfiehlt das Google Chrome-Team die Verwendung dieser Option nicht, da sie den Hauptthread blockiert und Web-Worker und Service-Worker unzugänglich macht. Sie haben ein Experiment gestartet: KV Storage, als bessere Version, aber es war nur ein Experiment und es scheint noch keine Fortschritte zu geben. 🎜🎜localStorage API ist als window.localStorage verfügbar und kann nur UTF-16-Strings speichern. Bevor wir die Daten in localStorage speichern, müssen wir sicherstellen, dass sie in einen String konvertiert werden. Die drei Hauptfunktionen sind: 🎜
  • setItem('key', 'value')
  • getItem( ' key')
  • removeItem('key')
🎜Sie sind alle synchronisiert und daher einfach zu verwenden, aber sie Blockiere den Hauptthread. 🎜🎜Es ist erwähnenswert, dass localStorage einen Zwilling namens sessionStorage hat. Der einzige Unterschied besteht darin, dass in sessionStorage gespeicherte Daten nur für die aktuelle Sitzung bestehen bleiben, die API jedoch dieselbe ist. 🎜🎜Das ist so einfach, ich glaube, jeder hat es verwendet. 🎜🎜IndexedDB API🎜🎜IndexedDB ist eine moderne Speicherlösung im Browser. Es kann große Mengen strukturierter Daten speichern, sogar Dateien und Blobs. Wie jede Datenbank indiziert IndexedDB Daten, um Abfragen effizient auszuführen. Die Verwendung von IndexedDB ist komplizierter. Wir müssen eine Datenbank und Tabellen erstellen und Transaktionen verwenden. 🎜🎜Im Vergleich zu localStorage erfordert IndexedDB mehr Code. Im Beispiel habe ich die native API mit einem Promise-Wrapper verwendet, ich empfehle jedoch dringend, eine Bibliothek eines Drittanbieters zu verwenden, um Ihnen zu helfen. Was ich empfehle, ist localForage, da es dieselbe localStorage-API verwendet, die Implementierung jedoch schrittweise verbessert wird. Das heißt, wenn Ihr Browser IndexedDB unterstützt, wird es verwendet, wenn es nicht unterstützt wird verwendet wird, wird auf localStorage zurückgegriffen. 🎜🎜Schreiben wir etwas Code und gehen wir zu unserem Beispiel für Benutzerpräferenzen! 🎜
<input>
<label>Dark theme</label>
rrree🎜Effekt🎜🎜Erfahren Sie mehr über die verschiedenen Speichertypen in Browsern🎜🎜idb ist ein Promise-Wrapper, den wir anstelle der ereignisbasierten Low-Level-API verwenden. Als erstes ist zu beachten, dass jeder Zugriff auf die Datenbank asynchron erfolgt, was bedeutet, dass wir den Hauptthread nicht blockieren, was einen großen Vorteil im Vergleich zu localStorage darstellt. 🎜🎜Wir müssen eine Verbindung zur Datenbank herstellen, damit diese in der gesamten Anwendung zum Lesen und Schreiben verwendet werden kann. Wir geben der Datenbank einen Namen my-db, eine Schemaversion 1 und eine Aktualisierungsfunktion, um Änderungen zwischen Versionen anzuwenden, ähnlich wie bei Datenbankmigrationen. Unsere Datenbankarchitektur ist sehr einfach: Es gibt nur einen Objektspeicher preferences. Der Objektspeicher entspricht einer SQL-Tabelle. Um in die Datenbank zu schreiben oder aus ihr zu lesen, müssen Sie Transaktionen verwenden, was den mühsamen Teil der Verwendung von IndexedDB darstellt. Schauen Sie sich die neuen Funktionen save und load in der Demo an. 🎜🎜Es besteht kein Zweifel daran, dass IndexedDB im Vergleich zu localStorage mehr Overhead und eine steilere Lernkurve hat. Im Schlüsselwert-Fall ist es möglicherweise sinnvoller, localStorage oder eine Bibliothek eines Drittanbieters zu verwenden, was uns dabei hilft, effizienter zu sein. 🎜
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;
rrree🎜Effekt🎜🎜Erfahren Sie mehr über die verschiedenen Speichertypen in Browsern🎜🎜In dieser Datenbank können Sie Hunderte von Megabyte oder mehr speichern. Sie können alle Ihre Pokémon in IndexedDB speichern, sie offline schalten und sogar indizieren! Dies ist definitiv eine Option zur Speicherung von Anwendungsdaten. 🎜🎜Ich habe die Implementierung des dritten Beispiels übersprungen, da IndexedDB in diesem Fall keinen Unterschied zu localStorage macht. Selbst mit IndexedDB teilen Benutzer die ausgewählte Seite nicht mit anderen oder speichern sie für die zukünftige Verwendung als Lesezeichen. Keines davon ist für diesen Anwendungsfall geeignet. 🎜

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;

效果还是跟前面一样

Erfahren Sie mehr über die verschiedenen Speichertypen in Browsern

将用户的喜好保存在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;

效果还是一样

Erfahren Sie mehr über die verschiedenen Speichertypen in Browsern

我们可以通过 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);

效果

Erfahren Sie mehr über die verschiedenen Speichertypen in Browsern

就像我们的分页例子一样,临时应用状态是最适合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

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

Das obige ist der detaillierte Inhalt vonErfahren Sie mehr über die verschiedenen Speichertypen in Browsern. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:segmentfault.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen