造一个 idb-keyval 轮子

本文作者通过实现一个简单的 idb-keyval 库,讲解如何使用 IndexedDB 实现类似 localStorage 的功能。从需求分析、原始实现到逐步优化,包括 promisify、封装公共逻辑、创建单例 Store、增删改查接口以及遍历所有 key-val 的方法,作者详细介绍了每个步骤。最后,作者分享了自己的学习感受,认为研究和改进小库是提升技能的好方法。
摘要由CSDN通过智能技术生成

文章源码:https://github.com/Haixiang6123/my-idb-keyval

预览链接:http://yanhaixiang.com/my-idb-keyval/

参考轮子:https://github.com/jakearchibald/idb-keyval

你真的会使用 indexdb 么

相信不少人看过阮一峰的 《浏览器数据库 IndexedDB 入门教程》。我自己的感觉是依然不会使用 indexedDB,感觉每一步操作都很简单但是就是不会把整个流程跑通。

正好最近用到了 idb-keyval 这个库,阅读了一下源码后终于是有点感觉了。下来就从一个简单的例子开始,一步步来造一个 idb-keyval 库吧。

一个简单的需求

我们都知道 localStorage 的用法,现在就用 indexedDB 来实现 localStorage 的用法。

丑陋的实现

根据阮一峰老师的教程,假如我们要实现 getItem 方法,用最最最原生的方法就是:

const dbName = 'key-val'
const storeName = 'keyval'

export function uglyGet(key: string) {
   
  // 打开数据库
  const openDBRequest = indexedDB.open(dbName)

  // 创建表
  openDBRequest.onupgradeneeded = function () {
   
    openDBRequest.result.createObjectStore(storeName)
  }

  // 失败回调
  openDBRequest.onerror = () => console.log('出错啦')

  // 成功回调
  openDBRequest.onsuccess = () => {
   
    // 获取数据库
    const db = openDBRequest.result

    // 获取数据库里的 store
    const store = db.transaction(storeName, 'readonly').objectStore(storeName)

    // 获取值操作
    const getRequest = store.get(key);

    getRequest.onsuccess = function() {
   
      // 获取到值
      console.log(`获取 ${
     key} 成功`, this.result)
    }
    getRequest.onerror = function() {
   
      console.log(`获取 ${
     key} 失败`)
    }
  }
}

上面做了以下操作:

  • 打开 key-val 数据库
  • 添加 keyval 对象仓库(如果没有的话)
  • 获取 key 对应的 value 值,并显示 this.result

看看看看,现在取个 value 还有没有点规矩了?

咱们的诉求是什么呀?是通过一个简单的 API 来获取一个 value,里面的逻辑应该只要调几个接口就够了。你让我造这么多个回调和监听,只为拿一个 value 值。丢不丢人?恶不恶心?难看不难看呐?

下面就来一步一步改造上面的代码。

promisify

看到回调,很容易就想到了利用 Promise 来进行封装,封装之后就可以用 await-async 来写代码了,避免回调地狱。上面主要是 request 来执行一些操作,所以我们应该将这些操作进行 promisify:

/**
 * 将 request 变为 Promise 对象
 * indexeddb 操作成功后会调用 onsuccess,因此绑定到 resolve
 * indexeddb 操作失败后会调用 onerror,因此绑定到 reject
 * @param request
 */
export function promisifyRequest<T = undefined>(request: IDBRequest<T> | IDBTransaction): Promise<T> {
   
  return new Promise<T>((resolve, reject) => {
   
    // @ts-ignore
    request.onsuccess = () => resolve(request.result)
    // @ts-ignore
    request.onerror = () => reject(request.error)
  });
}

然后可以改写成 promise.then 的写法:

export async function uglyGet(key) {
   
  // 打开数据库
  const openDBRequest = indexedDB.open(dbName)

  // 创建表
  openDBRequest.onupgradeneeded = () => openDBRequest.result.createObjectStore(storeName)

  // 失败回调
  return promisifyRequest(openDBRequest)
    .then(db => {
   
      // 获取数据库里的 store
      const store = db.transaction(storeName
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

写代码的海怪

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值