前言
前端的储存方案有很多,我们常用的存储方式主要由两种:cookie、webStorage(localStorage 和 sessionStorage)
cookie 和 session
cookie 和 session 都是普遍用来跟踪浏览用户身份的会话方式。
cookie 和 session的区别:
-
cookie存放在浏览器中,而session存放在服务器。
-
cookie不是很安全,别人可以分析存放在本地的cookie并进行cookie欺骗,所以一般存放一些不敏感信息;而session更安全。
-
cookie一般4kb大,很多浏览器都限制一个域名最多保存 50 个 cookie,而session并没有大小的要求,但是当session较大的时候会影响性能,所以会定时销毁。
-
cookie中只能保管ASCII字符串,并需要通过编码方式存储为Unicode字符或者二进制数据。session中能够存储任何类型的数据,包括且不限于string,integer,list,map等。
cookie、localStorage 以及 sessionStorage 的异同点:
分类 | 生命周期 | 存储容量 | 存储位置 | 使用场景 |
---|---|---|---|---|
cookie | 默认保存在内存中,随浏览器关闭失效(如果设置过期时间,在到过期时间后失效) | 4KB | 保存在客户端,每次请求时都会带上 | 存储用户信息 |
localStorage | 理论上永久有效的,除非主动清除。 | 5MB(不同浏览器情况不同,safari 2.49M) | 保存在客户端,不与服务端交互。节省网络流量 | 适合长期保存在本地的数据,比如页面的默认偏好配置、长期登录 |
sessionStorage | 仅在当前网页会话下有效,关闭页面或浏览器后会被清除。 | 5MB(部分浏览器没有限制) | 同上 | 敏感账号一次性登录 |
indexedDB
介绍
IndexedDB 是一种底层 API,用于在客户端存储大量的结构化数据(也包括文件/二进制大型对象(blobs)。该 API 使用索引实现对数据的高性能搜索。虽然 Web Storage 在存储较少量的数据很有用,但对于存储更大量的结构化数据来说力不从心。而 IndexedDB 提供了这种场景的解决方案。
IndexedDB 是一种 NoSQL 数据库 (非关系型数据库,使用键值对存储数据,且结构不固定,非常类似JavaScript中的纯对象),和关系型数据库不同的是,IndexedDB是面向对象的,它存储的是Javascript对象,类似 mangoDB的存储方式。
使用场景
-
缓存大文件: 音视频 Blod 格式、图片文件流、 Base64资源。
-
WebGL、3D模型资源: 用来存储大量的 hdr、glb、gltf 等文件。
-
即时聊天工具(IM),大量消息需要存在本地。
-
固定的键值对: 数据字典、存储国标数据。
-
离线 Web 应用程序。
-
笔记软件:如我常用的Notion这种类型的软件可能会使用到indexedDB这项技术,当用户没有网络时离线储存数据,并且当有网络时再将离线储存的数据上传至服务器。
-
网站上的富文本编辑器:数据量大,且需要返回上一步,草稿等功能。这类功能讲数据放在服务端会出现各种问题是不现实的,所以就需要接入客户端数据库来解决。
-
股票金融类的统计图数据:这些数据都需要实时展示且过去数据基本不会改变,可以把已加载过的数据缓存在客户端来减少服务端的压力。
MDN文档
developer.mozilla.org/zh-CN/docs/...
兼容

特点
-
非关系型数据库(NoSql):我们都知道MySQL等数据库都是关系型数据库,它们的主要特点就是数据都以一张二维表的形式存储,而Indexed DB是非关系型数据库(非关系型数据库,使用键值对存储数据,且结构不固定,非常类似JavaScript中的纯对象)。
-
键值对储存:IndexedDB 内部采用对象仓库存放数据。所有类型的数据都可以直接存入,包括 JavaScript 对象。对象仓库中,数据以"键值对"的形式保存,每一个数据记录都有对应的主键,主键是独一无二的,不能有重复,否则会抛出一个错误。
-
持久化存储:IndexedDB存储的数据,会永远存在,除非手动删除数据库。
-
异步操作:IndexedDB 执行的操作是异步执行的,以免阻塞应用程序 (IndexedDB 最初包括同步和异步 API,有需要可以重新引入同步 API)。用户依然可以进行其他操作,这与 LocalStorage 形成对比,后者的操作是同步的。异步设计是为了防止大量数据的读写,拖慢网页的表现。
-
支持事务:IndexedDB 支持事务(transaction),这意味着一系列操作步骤之中,只要有一步失败,整个事务就都取消,数据库回滚到事务发生之前的状态,不存在只改写一部分数据的情况。
-
同源策略:IndexedDB 受到同源限制,每一个数据库对应创建它的域名。网页只能访问自身域名下的数据库,而不能访问跨域的数据库。
-
储存空间大:IndexedDB 的储存空间非常大,具体取决本地磁盘与浏览器限制,Chrome67 之前的版本是50%的硬盘空间,因此,如果硬盘驱动器是 500GB,那么浏览器的总存储容量为 250GB。
-
支持二进制储存:IndexedDB 不仅可以储存字符串,还可以储存二进制数据(ArrayBuffer 对象和 Blob 对象)
优劣:
-
优势:
- 可以存储大量结构化数据,容量较大。
- 提供异步 API,不会阻塞主线程。
-
劣势:
- API 相对复杂,使用起来可能较为复杂,学习成本较高。
- 不支持所有浏览器,需要考虑兼容性问题。
第三方库 localForage 的出现几乎抹平了这个缺陷,让我们轻松无负担的在浏览器中使用 indexedDB。
localForage
localForage 是 一个简单的 Polyfill,提供了简单的客户端数据存储的值语法。它在后台使用 IndexedDB,并在不支持 IndexedDB 的浏览器中回退到 WebSQL 或 localStorage。
什么是Polyfill?
polyfill (polyfiller),指的是一个代码块。这个代码块向开发者提供了一种技术, 这种技术可以让浏览器提供原生支持,抹平不同浏览器对API兼容性的差异。 --《介绍HTML5》
localForage 的使用
- 安装
css
npm i localforage
- 引用
javascript
import localforage from 'localforage'
- 创建一个 indexedDB
php
const myIndexedDB = localforage.createInstance({
name: 'myIndexedDB',
})
- 存值
scss
myIndexedDB.setItem(key, value)
- 取值
由于indexedDB的存取都是异步的,建议使用 promise.then() 或 async/await 去读值
javascript
myIndexedDB.getItem('somekey').then(function (value) {
// we got our value
}).catch(function (err) {
// we got an error
});
or
javascript
try {
const value = await myIndexedDB.getItem('somekey');
// This code runs once the value has been loaded
// from the offline store.
console.log(value);
} catch (err) {
// This code runs if there were any errors.
console.log(err);
}
- 删除某项
arduino
myIndexedDB.removeItem('somekey')
- 重置数据库
scss
myIndexedDB.clear()
以上是比较常用的方式,细节及其他使用方式请参考官方中文文档
在 VUE 中推荐配合 Pinia 使用 localForage
如果你想使用多个数据库,建议通过 pinia 统一管理所有的数据库,这样数据的流向会更明晰,数据库相关的操作都写在 store 中,让你的数据库更规范化。
typescript
// store/indexedDB.ts
import { defineStore } from 'pinia'
import localforage from 'localforage'
export const useIndexedDBStore = defineStore('indexedDB', {
state: () => ({
filesDB: localforage.createInstance({
name: 'filesDB',
}),
usersDB: localforage.createInstance({
name: 'usersDB',
}),
responseDB: localforage.createInstance({
name: 'responseDB',
}),
}),
actions: {
async setfilesDB(key: string, value: any) {
this.filesDB.setItem(key, value)
},
}
})
使用的时候,就直接调用 store 中的方法
javascript
import { useIndexedDBStore } from '@/store/indexedDB'
const indexedDBStore = useIndexedDBStore()
const file1 = {a: 'hello'}
indexedDBStore.setfilesDB('file1', file1)
indexedDB存储和localStorage存储对比
-
indexedDB存储IE10+支持,localStorage存储IE8+支持,后者兼容性更好;
-
indexedDB存储比较适合键值对较多的数据,我之前不少项目需要存储多个字段,使用的是localStorage存储,结果每次写入和写出都要字符串化和对象化,很麻烦,如果使用indexedDB会轻松很多,因为无需数据转换。
-
indexedDB存储可以在workers中使用,localStorage貌似不可以。这就使得在进行PWA开发的时候,数据存储的技术选型落在了indexedDB存储上面。
和PWA技术的关系 PWA全称为"Progressive Web Apps",渐进式网页应用。 (vue: 渐进式 JavaScript 框架)
渐进式是指 表现为缓慢的、持续的量的积累过程.
PWA的核心技术包括:
- Web App Manifest -- 在主屏幕添加app图标,定义手机标题栏颜色之类
- Service Worker -- 缓存,离线开发,以及地理位置信息处理等
- App Shell -- 先显示APP的主结构,再填充主数据,更快显示更好体验
- Push Notification -- 消息推送,之前有写过"简单了解HTML5中的Web Notification桌面通知"
Web SQL Database
WebSQL(已于 2010 年 9 月 18 日起弃用)
-
优势:
- 提供 SQL 数据库的操作方式,适用于复杂的数据操作。
-
劣势:
- 已被废弃,不被推荐使用,不支持所有浏览器。
indexedDB为何替代了Web SQL Database
cacheStorage
在网站上浏览页面时,浏览器会下载许多资源,例如 HTML、CSS、JavaScript 文件和图像。为了提高网页加载速度和降低网络流量,浏览器使用缓存来存储这些资源,以便在将来的页面访问中能够更快地获取它们。CacheStorage 是Service Worker API下的接口,截图如下:

其中,Cache直接和请求打交道,CacheStorage和Cache对象打交道,我们可以直接使用全局的caches属性访问CacheStorage,例如,虽然API上显示的是CacheStorage.open(),但我们实际使用的时候,直接caches.open()就可以了。
至于 Cache 和 CacheStorage 具体的增删改查API直接去这里一个一个找,Service Worker API的知识体量实在惊人,若想要系统学习,那可要做好充足的心理准备了。

使用场景
- 静态资源缓存: 将网站的静态资源(例如 CSS、JavaScript、图片等)缓存起来,以便在用户再次访问时能够更快地加载页面。
- 离线访问: 使用 Cache API 可以缓存应用程序的核心资源,使用户在离线状态下仍然能够访问内容,提供更好的离线体验。
- Service Worker 缓存: Service Worker 是一种运行在浏览器后台的脚本,可以拦截网络请求并将其缓存起来,从而实现更高级的缓存控制和离线功能。
- 数据预取和预加载: 在用户访问页面之前,提前缓存可能需要的资源,以减少页面加载时间。
- 动态内容缓存: 缓存 API 还可以用于缓存动态生成的内容,如 API 响应,以减轻服务器负担并提高响应速度。
- 减少网络请求: 缓存 API 可以减少重复的网络请求,从而降低服务器压力,提高性能。
- 图片懒加载: 缓存 API 可以用于懒加载图片,即只在用户需要时才加载图片资源,从而节省带宽和提高页面加载速度。
- 数据更新与刷新策略: 缓存 API 可以用于实现数据更新和刷新策略,确保用户始终获取最新的数据。
- 资源预加载: 提前缓存可能需要的资源,以便在用户访问相关页面时能够更快地加载内容。
- 响应速度优化: 缓存可以显著提高页面加载速度,从而改善用户体验和 SEO。
优劣:
-
优势:
- 适用于缓存资源,如图片、样式等,提高性能。
- 可以灵活控制缓存过程,支持更复杂的缓存策略。
-
劣势:
- 主要用于缓存资源,不适合存储业务数据