基于indexedDB的缓存解决方案

2,543 阅读3分钟

基于indexedDB的缓存解决方案

参考文档:wangdoc.com/javascript/…

摘要

近期由于缓存问题折腾的头疼、发现前端缓存数据量过大导致localstorage无法储存、后面查阅发现localstorage只能储存5~10mb的数据,但是indexedDB可以储存250mb的数据,对比下当然选择indexedDB拉,但是问题来了,localstorage是同步、indexedDB是异步,这样一来不就没办法解决问了吗,网上找了一圈,结果没有发现更好的indexedDB的封装包,于是迫不得已自己写了一个,并且发布到了npm和github,有兴趣的可以去看看,点个星星或者有想法的提个issue。

开源地址

github.com/zmkwjx/baik…

www.npmjs.com/package/@ba…

indexedDB简介【引用】

随着浏览器的功能不断增强,越来越多的网站开始考虑,将大量数据储存在客户端,这样可以减少从服务器获取数据,直接从本地获取数据。

现有的浏览器数据储存方案,都不适合储存大量数据:Cookie 的大小不超过 4KB,且每次请求都会发送回服务器;LocalStorage 在 2.5MB 到 10MB 之间(各家浏览器不同),而且不提供搜索功能,不能建立自定义的索引。所以,需要一种新的解决方案,这就是 IndexedDB 诞生的背景。

通俗地说,IndexedDB 就是浏览器提供的本地数据库,它可以被网页脚本创建和操作。IndexedDB 允许储存大量数据,提供查找接口,还能建立索引。这些都是 LocalStorage 所不具备的。就数据库类型而言,IndexedDB 不属于关系型数据库(不支持 SQL 查询语句),更接近 NoSQL 数据库。

IndexedDB 具有以下特点。

(1)键值对储存。 IndexedDB 内部采用对象仓库(object store)存放数据。所有类型的数据都可以直接存入,包括 JavaScript 对象。对象仓库中,数据以“键值对”的形式保存,每一个数据记录都有对应的主键,主键是独一无二的,不能有重复,否则会抛出一个错误。

(2)异步。 IndexedDB 操作时不会锁死浏览器,用户依然可以进行其他操作,这与 LocalStorage 形成对比,后者的操作是同步的。异步设计是为了防止大量数据的读写,拖慢网页的表现。

(3)支持事务。 IndexedDB 支持事务(transaction),这意味着一系列操作步骤之中,只要有一步失败,整个事务就都取消,数据库回滚到事务发生之前的状态,不存在只改写一部分数据的情况。

(4)同源限制。 IndexedDB 受到同源限制,每一个数据库对应创建它的域名。网页只能访问自身域名下的数据库,而不能访问跨域的数据库。

(5)储存空间大。 IndexedDB 的储存空间比 LocalStorage 大得多,一般来说不少于 250MB,甚至没有上限。

(6)支持二进制储存。 IndexedDB 不仅可以储存字符串,还可以储存二进制数据(ArrayBuffer 对象和 Blob 对象)。

@baikbingo/cache封装包使用

获取对象、配置

安装

npm i @baikbingo/cache -S

本封装包(以下简介cache)可以支持vue.use,也可以不直接获取实例,自己另外封装函数。

import cache from "@baikbingo/cache";
import Vue from "vue";
Vue.use(cache);
// 或者
import { createCache } from "@baikbingo/cache";
app.prototype.$cache = createCache();

推荐使用cache的hook函数createCache另外封装:

import { createCache } from "@baikbingo/cache";
const cahce = createCache({
  databaseName: "cache", // 数据库名称
  tableName: "localStorage", // 表名
  version: 1 // 版本号
});
export default cahce;

获取缓存操作

每次set操作cache都会将数据放入内存中,如果是初始化操作可以直接使用get或者syncGet获取数据

const cahce = createCache();

// 异步
cache.get(key).then(res => {
  console.log("结果", res);
});

// 同步
const res = cache.syncGet(key);

如果是刷新操作,并没有执行set怎么办?首先,函数会内部调用readAll方法去取indexedDB内部的数据,但是这个操作是异步的,所以不能保证浏览器取数据的时候使用syncGet能从内存中拿到数据;或者如果你的操作可以接受异步的话,可以直接使用get方法(这个方法是直接读取数据、如果没有在内存中拿到数据则会取indexedDB中的数据)。

// 同步数据是要保证 数据遍历完成情况下才能获取(readAll)
// 所以可以在获取数据之前,重新赋值一下数据
// 在readAll方法下get一定能生效
cache.readAll().then(() => {
  const res = cache.syncGet(key);
});
// 或者
await cache.readAll();
const res = cache.syncGet(key);

如果跟store(全局状态管理插件)结合呢?可以在路由守卫或者初次挂载实例的时候执行readAll操作,比如vuex:

export default {
  create() {
    cache.readAll().then(() => {
      this.$store.state.token = cache.syncGet("token")
    })
  }
}

更多异步操作

const cahce = createCache();
cache.set(key, value);
cache.del(key);
cache.clear();

更多同步操作

const cahce = createCache();
cache.syncSet(key, value);
cache.syncDel(key);
cache.syncClear();