什么?项目中还没使用过indexDB?

409 阅读3分钟

一、使用场景

:你是什么?

indexDB:我也是浏览器的一种存储,跟localStorage、sessionStorage、cookie一样,可以缓存数据;

:平时用上边说的三个就够了,你有哪些优势呢?

indexDB:localStorage跟sessionStorage存储空间5M左右,cookie只有4K,那如果要存储比5M大的数据该怎么办呢?我的存储空间要大很多,一般来说不少于250M

:大多数项目也不需要存这么多内容,什么时候用你呢?

indexDB:比如:

  • 1、IM 相关的项目,聊天记录或者一些用户的信息,这些数据积累下来,量就比较大了;
  • 2、接口比较多的页面,可以使用我做接口数据缓存,减少下次渲染时间;
  • 3、某个接口返回全量数据(数万条或以上),由客户端做分页加载,可以放到我这里减少内存占用;
  • 4、静态资源的缓存,可以转成base64然后用我存储;
  • 等等..
  • 总之上边localStorage、sessionStorage、cookie存不下的数据都可以考虑用我;

:👍🏻👍🏻👍🏻

二、使用indexDB第三方库

为了提高开发效率,操作indexDB推荐使用github上最高star的第三方库 dexie.js

这个库使用promise封装,使用起来也比较顺手

image.png

项目中集成dexie

1、安装依赖

npm install dexie

2、创建一个db、表

  • db.js
import Dexie from 'dexie';

//创建db
const db = new Dexie('myDatabase');
//创建表
db.version(1).stores({
  friends: 'id, name, age', // 主键跟索引字段
});

3、操作db 更多操作参考文档

  • demo.js
//增,也可以用put
await db.friends.add({
  id: '1',
  name: "小名",
  age: 18,
});

//删
await db.friends
  .where("name").equals('小名')
  .delete()
  
//改 put操作 在对象存储中添加新对象或替换现有对象。
await db.friends.put({
  id: '1',
  name: "小名",
  age: 19,
})

//查
await db.friends.get('1')

怎么样,有了第三方库的加持,开发是不是爽了很多,使用起来也没那么复杂;

三、项目中使用dexie缓存接口数据

1、把上边db.js封装下

  • db.js
import Dexie from "dexie"

/* 当前数据库版本,修改表信息记得改版本+1 */
const version = 2;

/* 表数据 */
let tableList = [
  /* 接口信息缓存 */
  {
    name: "requestCache",
    index: "id, res",
    columns: {
      id: "",/* JSONString config */
      res: "",/* 返回值 */
      ts: 0/* 时间戳 */
    },
    cacheTs: 1000 * 60 * 60 * 24 * 30 /* 1月 */
  },
]

class DexieDB {

  db = {}

  /* 初始化 */
  init(dbName = "cache") {
    this.db = new Dexie(dbName);

    console.log("indexDB->db创建成功")
    this.initTable()
  }

  /* 初始化table */
  initTable() {
    let tableObj = {}
    tableList.map((item) => {
      tableObj[item.name] = item.index
    })


    this.db.version(version).stores(tableObj)
    console.log("indexDB-> 表创建成功", tableObj)
  }

  /* 清理缓存,可以在页面打开时候自己找地方调用,清理过期缓存 */
  clearCache(){
    let now = +new Date()
    tableList.map(async (item) => {
      const {cacheTs} = item;

      if(!cacheTs) return;

      let res = await this.db[item.name].where("ts").below((now-cacheTs)).delete()

      console.log("indexDB->清理缓存", item.name, res)
    })

  }
}

export default new DexieDB()

2、封装一个链式调用工具类,请求是用的axios

export class AjaxAndCache {

  constructor(params) {
    //axios参数
    this.params = params;
    //缓存用的主键id数据
    this.cacheKey = JSON.stringify(this.params)
  }
  
  //错误回调
  errCB;
  //接口是否返回了
  cancel = false;
    
  //读缓存
  cache(cb) {
    this.cancel = false;
    const {
      url,
      method,
      params,
      data
    } = this.params;

    try {
      //读取缓存
      dexieDB.db.requestCache.get(this.cacheKey).then((res) => {
        //如果接口返回快则直接return,不用缓存数据
        if(this.cancel) return ;
        cb(res?.res ?? {})
      }).catch(console.error)
    } catch (error) {
      console.error(error)
      cb({})
    }
    
    return this
  }
    
  //请求数据
  then(cb) {
    req.ajax(this.params).then((res) => {
      const {
        url,
        method,
        params,
        data
      } = this.params;

      // 更新requestCache当前接口数据
      try {
        //存储缓存
        dexieDB.db.requestCache.put({
          id: this.cacheKey,
          res: res,
          ts: +new Date()
        }).catch(console.error)
      } catch (error) {
        console.error(error)
      }
      cb(res);
      this.cancel = true;
    }).catch((err) => {
      this.errCB && this.errCB(err)
    })

    return this
  }
    
  //报错
  catch (cb) {
    this.errCB = cb;

    return this;
  }
}

3、使用工具类存储并使用缓存

<template>
  <div>
     组件渲染
  </div>
</template>

<script setup>
import {provide, onMounted, ref } from "vue";
import {AjaxAndCache} from "@/req"

const dataSource = ref(null);

const init = async () => {
  new AjaxAndCache({
    url: "/api/接口",
    method: "get"
  }).cache((res)=>{
    //缓存数据
    dataSource.value = res;
  }).then((res)=>{
    //接口数据
    dataSource.value = res;
  }).catch(console.error)
}

onMounted(init)

provide('dataSource', dataSource)
</script>

<style lang="less" scoped>
</style>

兼容性

image.png

结语

希望能帮大家扩展一下思路

大家根据自己业务场景判断是否需要indexDB,怎么使用