调查IndexedDB封装库 - 第二部分

410 阅读4分钟

在昨天的文章中,我谈到了我对再次挖掘 IndexedDB 的兴趣,特别是,我想研究一些使使用该功能更容易的库。在第一篇文章中,我描述了一个基本的 "联系人 "应用程序,并演示了使用 IndexedDB 添加持久性所需的代码。今天,我将更新我的应用程序,以利用一个名为Dexie 的包装库。

Dexie 是 IndexedDB 的一个非常简单的封装器,并且对包括 Vue、React、Svelte 和 Angular 在内的框架有反应式支持。Dexie是一个免费的库,但他们也出售一种叫做Dexie Cloud的商业同步服务。它使用了Promises,这使得它与async/await的使用更加简单。我建议你看一下广泛的文档,因为我将只关注我的应用程序转换所需的部分。

和以前一样,我将跳过讨论DOM的东西,只关注与持久性有关的部分。

包括Dexie

包括Dexie就像添加一个脚本ag和指向CDN一样简单,unpkg.com/dexie/dist/…

初始化数据库

还记得我说过与 Dexie 合作使 IndexedDB 变得简单吗?没有什么能比初始化更说明问题了。为了便于比较,这里是原始代码:

async function initDb() {
    return new Promise((resolve, reject) => {
        
        let request = indexedDB.open('contacts', 1);

        request.onerror = event => {
            alert('Error Event, check console');
            console.error(event);
        }
        
        request.onupgradeneeded = event => {
            console.log('idb onupgradeneeded firing');

            let db = event.target.result;

            let objectStore = db.createObjectStore('contacts', { keyPath: 'id', autoIncrement:true });
            objectStore.createIndex('lastname', 'lastname', { unique: false });
        };
        
        request.onsuccess = event => {
            resolve(event.target.result);
        };
    });
}

记住,你必须打开数据库,然后监听一个升级事件(这个事件在第一次访问时也被触发),并在那里做任何结构性设置。这涉及到创建存储和索引。我的演示没有做任何搜索,所以我不用担心这个问题。

这里是Dexie的版本:

async function initDb() {
    let db = new Dexie('contacts_dexie');
    db.version(1).stores({contacts:'++id'})
    return db;  
}

这真是令人震惊的小。公平地说,这实际上并没有创建数据库,它只是 "准备 "了你的网页。Dexie很聪明地推迟了做任何事情,直到你试图处理数据。但需要注意的是,如果你打开了devtools,并且正在查看你的数据库,你一开始就不会看到任何东西。

第二行定义了一个名为contacts 的存储。这个字符串值是你定义主键和索引的方式。因为我没有任何索引只有一个主键,所以它比较短。如果我想在姓氏属性上建立一个索引,它看起来会是这样的:

db.version(1).stores({contacts:'++id,lastName'})

简单的事情还能继续吗?

获取所有联系人

接下来是获取所有联系人的调用。这里是原始的:

async function getContacts() {
    return new Promise((resolve, reject) => {
        let transaction = db.transaction(['contacts'], 'readonly');
        
        transaction.onerror = event => {
            reject(event);
        };
        
        let store = transaction.objectStore('contacts');
        store.getAll().onsuccess = event => {
            resolve(event.target.result);
        };
    
    });
}

而现在是Dexie版本。

async function getContacts() {
    return await db.contacts.toArray();
}

如果你还没有印象,我不知道什么让你印象深刻

获取一个联系人

再一次,以前的版本:

async function getContact(key) {
    return new Promise((resolve, reject) => {
        let transaction = db.transaction(['contacts'], 'readonly');
        
        transaction.onerror = event => {
            reject(event);
        };
        
        let store = transaction.objectStore('contacts');
        store.get(key).onsuccess = event => {
            resolve(event.target.result);
        };
    
    });
}

而用Dexie:

async function getContact(key) {
    return await db.contacts.get(key);
}

保存联系人

如果你还记得,在以前的版本中,我们使用put API,让我们有一种方法来存储新的联系人以及更新现有的联系人。这里是原版:

async function persistContact(contact) {
    return new Promise((resolve, reject) => {
        
        let transaction = db.transaction(['contacts'], 'readwrite');
        transaction.oncomplete = event => {
            resolve();
        };
        
        transaction.onerror = event => {
            reject(event);
        };
        
        let store = transaction.objectStore('contacts');
        store.put(contact);
        
    });
}

然后是Dexie:

async function persistContact(contact) {
    await db.contacts.put(contact);
}

删除联系人

最后,让我们看看删除联系人的情况。这里又是原文:

async function removeContact(key) {
    return new Promise((resolve, reject) => {
        let transaction = db.transaction(['contacts'], 'readwrite');

        transaction.oncomplete = event => {
            resolve();
        };
        
        transaction.onerror = event => {
            reject(event);
        };
        
        let store = transaction.objectStore('contacts');
        store.delete(key);
        
    });
}

你可以猜一猜它在Dexie里有多少行:

async function removeContact(key) {
    return await db.contacts.delete(key);
}

全部内容

下面你会看到完整的应用程序。说实话,我几乎考虑过用Dexie这么简单的方法来删除我的持久化方法。但我也认为有一个处理DOM事件的方法和一个只专注于持久化的方法是很好的。这些函数可能只有一到两行,但这样的抽象化使我能够在以后进行架构上的改变。下面是最终的应用程序,再次原谅嵌入中略显混乱的格式。