【Vuejs】总结- Vue 存储插件的底层原理,你不知道的 localStorage API

2024-05-30 13:57:46 浏览数 (2)

前言

当谈到 Web 应用的客户端存储时,localStorage API 脱颖而出,它允许开发者直接在浏览器中存储键值对。

在开发 Vue 应用时,我们有时候需要将用户数据保存在本地,实现持久化存储。我们可以自己编写存储功能,也可以使用 Pinia 生态的存储插件,比如目前人气最高的 pinia-plugin-persistedstate,而这个插件的默认存储方案就是基于 localStorage 实现的。

在本文中,我们会深度学习 localStorage API 的优缺点和其他替代存储方案。

localStorage API 是什么

localStorage API 是浏览器的内置功能,使开发者能够在用户设备上持久存储少量数据。

localStorage 基于简单的键值对运行,允许开发者保存字符串等原始数据类型。即使用户关闭浏览器或离开页面,这些数据仍然可用。

localStorage 提供了一种便捷方案来维护状态和存储用户首选项,而无需依赖服务器端存储。

localStorage 基本法

localStorage 提供了多种交互方法,包括但不限于:

  • setItem
  • getItem
  • removeItem
  • clear

举个栗子,代码如下所示:

代码语言:javascript复制
// 使用 setItem 存储数据
localStorage.setItem('username', 'john_doe')
// 使用 getItem 检索数据
const storedUsername = localStorage.getItem('username')
// 使用 removeItem 删除数据
localStorage.removeItem('username')
// 清空所有数据
localStorage.clear()

使用 JSON 序列化存储复合数据

虽然 localStorage 擅长处理简单键值对,但它还通过 JSON 序列化支持更复杂的数据存储。利用 JSON.stringifyJSON.parse,我们可以存储和检索结构化数据,比如对象和数组。

举个栗子,代码如下所示:

代码语言:javascript复制
const cat = {
  name: '薛定谔',
  age: 18
}

// 存储 cat 对象
localStorage.setItem('cat', JSON.stringify(cat))
// 检索并解析 cat 对象
const storedCat = JSON.parse(localStorage.getItem('cat'))

localStorage 的缺陷

尽管 localStorage 十分便捷,但它存在某些限制:

  • 非异步阻塞 API:一个显著的缺点在于,localStorage 作为非异步阻塞 API 运行。这意味着,localStorage 执行的任何操作都可能会阻塞主线程,降低应用程序性能和响应速度,影响用户体验。
  • 受限的数据结构:与更高级的数据库不同,localStorage 仅限于简单的键值存储。这种限制使得它不适合存储负载的数据结构,或管理数据元素之间的关系。
  • 字符串化开销:localStorage 存储 JSON 数据需要先对数据字符串化,且在检索时需要先解析。这个过程会带来性能开销,可能会使操作速度减慢高达 10 倍。
  • 缺乏索引:localStorage 缺乏索引功能,很难根据特定条件执行有效搜索。这个限制会阻碍依赖复杂数据检索的应用程序。
  • 页面阻塞:在多页面环境中,一个页面的 localStorage 操作可能会独占 CPU 资源,影响其他页面的性能。
  • 存储限制:浏览器通常对每个 localStorage 数据源施加大约 5 MiB 的存储限制。

localStorage 的优势

与 IndexedDB 替代存储解决方案相比,localStorage API 速度惊人。localStorage 擅长高效处理迷你键值赋值。由于其简单性以及与浏览器的直接集成,修改 localStorage 数据的开销最小。

对于快速简单的数据存储场景,localStorage 仍然是一个不错的选择。

何时不适合 localStorage?

虽然 localStorage 十分便捷,但它可能并不适合所有场景。

考虑以下情况,其他替代方案可能更合适:

  • 数据必须可查询:如果您的应用依赖根据特定条件查询数据,那么 localStorage 无法提供必要的查询功能。数据检索可能导致代码效率低下和性能下降。
  • 大型 JSON 文档:localStorage 存储大型 JSON 文档会消耗大量内存,并降低性能。
  • 频繁的读写操作:localStorage 上过多的读写操作会导致性能瓶颈。
  • 缺乏持久性:如果您的应用无需跨会话持久数据,请使用内存中的数据结构,比如 Map/Set,为瞬态数据提供速度和效率。

localStorage 的替代方案

localStorage vs IndexedDB

IndexedDB 既可以存储键值对,也可以存储 JSON 文档。

localStorage 通常每个域名的存储限制约为 5-10MB 不同,IndexedDB 可以处理更大的数据集,且其对索引的支持可以高效查询。

但粉丝请注意,IndexedDB 缺乏可观察性,这是 localStorage 通过 storage 事件的专属功能。

此外,虽然 IndexDB 复杂查询的性能差强人意,但对于某些场景而言 IndexedDB 可能太慢。

代码语言:javascript复制
// localStorage 通过 storage 事件监测变化
// IndexedDB 缺少监测功能
addEventListener('storage', event => {})

对于那些希望利用 IndexedDB 的全部功能的人而言,建议使用 RxDB 或 Dexie.js 等封装库。这些库通过复杂查询和可观察性等功能强化了 IndexedDB

文件系统 API(OPFS)

另一个知识盲区是 OPFS(源私有文件系统)。这个 API 提供对基于源的沙盒文件系统的直接访问,该文件系统针对性能高度优化,并提供对其内容的就地写入访问。

OPFS 提供了令人印象深刻的性能优势。然而,使用 OPFS API 可能十分复杂,而且能且仅能在 WebWorker 中访问。

localStorage vs Cookie

Cookie 曾经是客户端数据存储的主流方案,但在现代 Web 开发中已经失宠。

虽然 Cookie 可以存储数据,但与 localStorage 相比,Cookie 的速度慢了大约 100 倍。此外,Cookie 包含在 HTTP 请求头中会影响网络性能。

因此,不建议在当代 Web 应用中使用 Cookie 存储数据。

localStorage vs WebSQL

尽管 WebSQL 为客户端数据存储提供了基于 SQL 的接口,但它是一种已废弃的技术。

WebSQL API 已经被现代浏览器淘汰,且缺乏 IndexedDB 等替代方案的鲁棒性。

此外,WebSQL 的速度通常比 IndexedDB10 倍左右,这使得它对于需要高效数据检索的应用而言不是最佳选择。

localStorage vs sessionStorage

在不需要会话外的数据持久性的场景下,开发者通常会“切换赛道”到 sessionStorage

sessionStorage 能且仅能在标签页或浏览器会话期间保留数据。它可以在页面重载和恢复后继续存在,为临时数据需求提供便捷的解决方案。

React Native 的异步存储

对于 React Native 开发者而言,AsyncStorage API 是首选解决方案,它类似 localStorage 的镜像行为,但具有异步支持。

由于并非所有 JS 运行时都支持 localStorage,因此 AsyncStorage 为 React Native 应用中的数据持久性提供了无缝集成的替代方案。

用于 Node 的 node-localstorage

由于 Node 中不存在原生的 localStorage,因此我们会在 Node 等的运行时收到错误 ReferenceError: localStorage is not defined

node-localstorage 模块弥补了这一差距。该模块在 Node 环境中拷贝了浏览器的 localStorage,确保数据存储功能的一致性。

浏览器扩展中的 localStorage

虽然谷歌 Chrome 和 Firefox 浏览器扩展支持 localStorage,但在大多数场景下,浏览器都会清除数据,比如当用户清除浏览历史记录时。

相反,Extension Storage API 应该用于浏览器扩展。与 localStorage 相比,这个 API 的异步执行,且所有操作都会返回 Promise

Extension Storage 还提供自动同步功能,以便在用户登录的浏览器的所有实例之间拷贝数据。它甚至能够存储 JSON 格式的对象而不是纯字符串。

Deno 和 Bun 中的 localStorage

Deno 运行时有一个有效的 localStorage API,因此运行 localStorage.setItem() 等方法会奏效,且 localStorage 的数据会在多次运行中保留。

Bun 目前不支持 localStorage API。试试就逝世,会直接报错 ReferenceError: Can't find variable: localStorage。要在 Bun 中本地存储数据,可以使用 bun:sqlite 模块。

总结

在现代 Web 开发领域,localStorage 是轻量级数据的存储神器,其简单性和速度使其成为迷你键值分配的最佳方案。

然而,随着应用复杂性的增加,开发者必须仔细权衡他们的存储需求。

对于需要高级查询、复杂数据结构或大容量操作的场景,IndexedDB 等替代方案、RxDB 等封装库或 Deno 等运行时的 API 可以提供更强大的解决方案。

0 人点赞