神奇,前端不用redis也能实现消息队列——indexedDB

329 阅读2分钟

引言

在JS开发过程中,我们常常会用到 async/await的写法,来实现异步编程,但是这样的操作也会产生并发编程的常见问题。在后端处理上,我们会使用共享内存的lock锁机制,CSP/Actor机制等常见的类库方案,也会使用sqlite、mysql、redis这些具备transaction(事务)特性的数据库来实现消息队列。而此次在Browser前端开发中,我尝试用IndexedDB来实现对async/await的解决方案。

什么是IndexedDB

在浏览器中,我们更多接触到的是Cookie和LocalStorage。

在mdn中是这样介绍:

IndexedDB 是一个事务型数据库系统,类似于基于 SQL 的 RDBMS。然而,不像 RDBMS 使用固定列表,IndexedDB 是一个基于 JavaScript 的面向对象数据库。IndexedDB 允许您存储和检索用键索引的对象;可以存储结构化克隆算法支持的任何对象。您只需要指定数据库模式,打开与数据库的连接,然后检索和更新一系列事务。

如何使用IndexedDB

IndexedDB版本支持情况

indexeddb_version.png

玩前端的都知道浏览器种类繁多,什么chrome系,webkit系,firefox系等。这里我建议使用JS库——jakearchibald/idb

引用

Using npm

$ npm install idb

// demo.js
import { openDB, deleteDB, wrap, unwrap } from 'idb';

async function doDatabaseStuff() {
const db = await openDB(…);
}

Using browser

  1. modules 写法

     <script type="module">
         import { openDB, deleteDB, wrap, unwrap } from 'https://cdn.jsdelivr.net/npm/idb@7/+esm';
    
         async function doDatabaseStuff() {
             const db = await openDB(…);
         }
     </script>
    
  2. 外部引用

     <script src="https://cdn.jsdelivr.net/npm/idb@7/build/umd.js"></script>
     <script>
     async function doDatabaseStuff() {
         const db = await idb.openDB(…);
     }
     </script>
    
基本操作

检测IndexedDB API是否生效

(() => {
    'use strict'

    if (!('indexedDB' in window)) {
        console.warn('IndexedDB not supported')
        return
    }

    //...IndexedDB code
})()

连接DB

(async () => {
    //...

    const dbName = 'mydbname'
    const storeName = 'store1'
    const version = 1 //versions start at 1

    const db = await openDB(dbName, version, {
        upgrade(db, oldVersion, newVersion, transaction) {
        const store = db.createObjectStore(storeName)
        }
    })
})()

创建数据

(async () => {
    //...
    const dbName = 'mydbname'
    const storeName = 'store0'
    const version = 1

    const db = await openDB(dbName, version,{
        upgrade(db, oldVersion, newVersion, transaction) {
        const store = db.createObjectStore(storeName)
        store.put('Hello world!', 'Hello')
        }
    })
})()

带事务创建数据

(async () => {
    //...
    const dbName = 'mydbname'
    const storeName = 'store0'
    const version = 1

    const db = await openDB(/* ... */)

    const tx = db.transaction(storeName, 'readwrite')
    const store = await tx.objectStore(storeName)

    const val = 'hey!'
    const key = 'Hello again'
    const value = await store.put(val, key)
    await tx.done
})()

根据 Key 读取数据

const key = 'Hello again'
const item = await db.transaction(storeName).objectStore(storeName).get(key)

读取所有keys数据

const items = await db.transaction(storeName).objectStore(storeName).getAllKeys()

读取所有values数据

const items = await db.transaction(storeName).objectStore(storeName).getAll()

删除数据库

const dbName = 'mydbname'
await deleteDB(dbName)

根据 Key 删除数据

(async () => {
    //...

    const dbName = 'mydbname'
    const storeName = 'store1'
    const version = 1

    const db = await openDB(dbName, version, {
        upgrade(db, oldVersion, newVersion, transaction) {
        const store = db.createObjectStore(storeName)
        }
    })

    const tx = await db.transaction(storeName, 'readwrite')
    const store = await tx.objectStore(storeName)

    const key = 'Hello again'
    await store.delete(key)
    await tx.done
})()

清除数据

await store.clear();

引用 A quick but complete guide to IndexedDB and storing data in browsers