10个客户端存储选项和何时使用它们

131 阅读5分钟

Ten Client-side Storage Options

在浏览器中存储和操作数据--也被称为客户端存储--在没有必要或不可能将数据发送到网络服务器的情况下很有用。

在浏览器中存储和操作数据的情况包括。

  • 保留客户端应用程序的状态--如当前屏幕、输入的数据、用户偏好等。
  • 访问本地数据或文件并有严格隐私要求的实用程序
  • 离线工作的渐进式网络应用程序(PWA)。

以下是存储浏览器数据的十种方法。

本文深入探讨了这十种在浏览器中存储数据的不同方式,包括它们的局限性、优点、缺点,以及每种技术的最佳用途。

在我们浏览这些选项之前,先简单介绍一下数据持久性 ...

数据持久性

一般来说,你存储的数据要么是。

  1. 持久性:直到你的代码选择删除它,或者
  2. 挥发性:它一直保留到浏览器会话结束,通常是在用户关闭标签时。

现实中的情况更加微妙。

持久性数据可以在任何时候被用户、操作系统、浏览器或插件阻止或删除。浏览器可以在接近分配给该存储类型的容量时决定删除较旧或较大的项目。

浏览器还记录页面状态。你可以从一个网站上浏览,然后点击回来,或者关闭并重新打开一个标签;页面看起来应该是相同的。被视为仅适用于会话的变量和数据仍然可用。

1.JavaScript变量

公制评论
容量没有严格的限制,但当你填满内存时,可能会出现浏览器变慢或崩溃的情况
读/写速度最快的选项
持久性差:数据会被浏览器刷新而抹去

在JavaScript变量中存储状态是最快速和最简单的选择。我相信你不需要一个例子,但 ...

const
  a = 1,
  b = 'two',
  state = {
    msg:  'Hello',
    name: 'Craig'
  };

优点。

  • 易于使用
  • 快速
  • 不需要序列化或反序列化

缺点。

  • 脆弱:刷新或关闭标签会抹去所有内容
  • 第三方脚本可以检查或覆盖全局(window )值

你已经在使用变量了。你可以考虑在页面卸载时永久地存储变量状态。

2.DOM节点存储

公制评论
容量没有严格限制,但对于大量数据来说并不理想
读/写速度快速
持久性差:数据可以被其他脚本或刷新抹去

大多数DOM元素,无论是在页面上还是在内存中,都可以在命名的属性中存储数值。使用以data- 为前缀的属性名是比较安全的。

  1. 该属性不会有相关的HTML功能
  2. 你可以通过dataset 属性来访问数值,而不是通过更长的.setAttribute().getAttribute()方法。

值是以字符串形式存储的,所以可能需要进行序列化和去序列化。比如说。

// locate <main> element
const main = document.querySelector('main');

// store values
main.dataset.value1 = 1;
main.dataset.state = JSON.stringify({ a:1, b:2 });

// retreive values
console.log( main.dataset.value1 ); // "1"
console.log( JSON.parse(main.dataset.state).a ); // 1

优点。

  • 你可以在JavaScript或HTML中定义值--比如说<main data-value1="1">
  • 对存储一个特定组件的状态很有用
  • DOM是快速的!(与流行观点相反)

缺点。

  • 脆弱:刷新或关闭标签会抹去一切(除非一个值被服务器渲染到HTML中)。
  • 只有字符串:需要序列化和反序列化
  • 较大的DOM会影响性能
  • 第三方脚本可以检查或重写值

DOM节点的存储速度比变量慢。在将组件的状态存储在HTML中比较实用的情况下,要少用它。

3.网络存储 (localStoragesessionStorage)

公制评论
容量每个域5MB
读/写速度同步操作:可能很慢
持久性数据保持到清空为止

Web Storage提供两个类似的API来定义名/值对。使用。

  1. window.localStorage 来存储持久性数据,以及
  2. window.sessionStorage 以在浏览器标签保持打开时保留会话专用数据(但见数据持久性)。

用以下方法存储或更新命名的项目 .setItem():

localStorage.setItem('value1', 123);
localStorage.setItem('value2', 'abc');
localStorage.setItem('state', JSON.stringify({ a:1, b:2, c:3 }));

.getItem() 检索它们。

const state = JSON.parse( localStorage.getItem('state') );

并用.removeItem() 删除它们。

localStorage.removeItem('state')

其他属性和方法包括。

改变任何值都会在连接到同一域的其他浏览器标签/窗口中引发一个存储事件。你的应用程序可以做出相应的反应。

window.addEventListener('storage', s => {

  console.log(`item changed: ${ s.key }`);
  console.log(`from value  : ${ s.oldValue }`);
  console.log(`to new value: ${ s.newValue }`);

});

优点是。

  • 简单的名/值对API
  • 会话和持久化存储选项
  • 良好的浏览器支持

劣势。

  • 只有字符串:需要序列化和反序列化
  • 非结构化数据,没有事务、索引或搜索
  • 同步访问会影响大型数据集的性能

网络存储是较简单的、较小的、临时性的数值的理想选择。对于存储大量的结构化信息来说,它不太实用,但你也许可以通过在页面卸载时写入数据来避免性能问题。

4.索引型数据库

公制评论
容量取决于设备。至少1GB,但可以达到剩余磁盘空间的60%。
读/写速度速度快
持久性数据保持到清空为止

IndexedDB提供了一个类似NoSQL的低级API来存储大量的数据。该存储可以被索引,使用事务进行更新,并使用异步方法进行搜索。

IndexedDB的API很复杂,需要一些事件杂耍。下面的函数在传递名称、版本号和可选的升级函数(当版本号改变时被调用)时打开一个数据库连接。

// connect
function dbConnect(dbName, version, upgrade) {

  return new Promise((resolve, reject) => {

    const request = indexedDB.open(dbName, version);

    request.onsuccess = e => {
      resolve(e.target.result);
    };

    request.onerror = e => {
      console.error(`indexedDB error: ${ e.target.errorCode }`);
    };

    request.onupgradeneeded = upgrade;

  });

}

下面的代码连接到一个myDB 数据库,并初始化一个todo 对象存储(类似于一个 SQL 表或 MongoDB 集合)。然后它定义了一个自动递增的键,名为id

(async () => {

  const db = await dbConnect('myDB', 1.0, e => {

    db = e.target.result;
    const store = db.createObjectStore('todo', { keyPath: 'id', autoIncrement: true });

  })

})();

一旦db 连接准备就绪,你就可以在一个事务中.add 新的数据项。

db.transaction(['todo'], 'readwrite')
  .objectStore('todo')
  .add({ task: 'do something' })
  .onsuccess = () => console.log( 'added' );

而且你可以检索值,例如第一个项目。

db.transaction(['todo'], 'readonly')
  .objectStore('todo')
  .get(1)
  .onsuccess = data => console.log( data.target.result );
  // { id: 1, task: 'do something' }

优点。

  • 灵活的数据存储,拥有最大的空间
  • 强大的交易、索引和搜索选项
  • 良好的浏览器支持

劣势。

  • 一个复杂的回调和基于事件的API

IndexedDB是可靠地存储大量数据的最佳选择,但你会希望获得一个包装库,如idbDexie.jsJsStore

继续阅读10个客户端存储选项和何时使用它们onSitePoint.