我应该每次打开一个IDBDatabase还是保持一个实例打开?

Kei*_*ith 6 javascript indexeddb

我有一个SPA应用程序,将进行多次读/写IndexedDB.

打开DB是一个带回调的异步操作:

var db; 
var request = window.indexedDB.open("MyDB", 2);

request.onupgradeneeded = function(event) { 
    // Upgrade to latest version...
}

request.onerror = function(event) { 
    // Uh oh...
}

request.onsuccess = function(event) {
    // DB open, now do something
    db = event.target.result;
};
Run Code Online (Sandbox Code Playgroud)

我可以通过两种方式使用此db实例:

  1. db在页面/ SPA的生命周期中保留一个实例?
  2. db.close()当前操作完成后调用并在下一次操作中打开一个新操作?

这两种模式都存在缺陷吗?保持indexedDB开放是否有任何风险/问题?每个open动作是否有开销/延迟(超过可能的升级)?

Jos*_*osh 9

我发现每次操作打开一个连接并不会显着降低性能。我已经运行本地 Chrome 扩展程序一年多了,它涉及大量 indexedDB 操作,并且已经对其性能进行了数百次分析,但从未见过打开连接成为瓶颈。瓶颈在于做一些事情,比如没有正确使用索引或存储大 blob。

基本上,不要根据性能来做决定。这真的不是连接方面的问题。

问题实际上是您的代码的人体工程学,您与 API 的对抗程度,以及您的代码在查看时的直观感受,您认为代码的稳定性如何,它对新人的欢迎程度(您自己的一个月后,或其他人)。这在处理阻塞问题时非常显着,也就是间接处理应用程序模态。

我个人的观点是,如果您对编写异步 Javascript 感到满意,请使用您喜欢的任何方法。如果您在使用异步代码时遇到困难,选择始终打开连接往往可以避免任何问题。我永远不会建议对异步代码较新的人使用单个全局页面生命周期变量。您还将在页面的整个生命周期内将变量留在那里。另一方面,如果您发现 async 微不足道,并且发现全局 db 变量更适合,请务必使用它。

编辑 - 根据您的评论,我想我会分享一些我个人喜好的伪代码:

function connect(name, version) {
  return new Promise((resolve, reject) => {
    const request = indexedDB.open(name, version);
    request.onupgradeneeded = onupgradeneeded;
    request.onsuccess = () => resolve(request.result);
    request.onerror = () => reject(request.error);
    request.onblocked = () => console.warn('pending till unblocked');
  });
}

async foo(bar) {
  let conn;
  try {
    conn = await connect(DBNAME, DBVERSION);
    await storeBar(conn, bar);
  } finally {
    if(conn)
      conn.close();
  }
}

function storeBar(conn, bar) {
  return new Promise((resolve, reject) => {
    const tx = conn.transaction('store');
    const store = tx.objectStore('store');
    const request = store.put(bar);
    request.onsuccess = () => resolve(request.result);
    request.onerror = () => reject(request.error);
  });
}
Run Code Online (Sandbox Code Playgroud)

使用 async/await,conn = await connect()在您的操作功能中添加额外的行不会有太多摩擦。


Jos*_*ell 5

每次打开连接可能会变慢,因为浏览器正在做更多的工作(例如,可能需要从磁盘读取数据)。否则,没有真正的不利方面。

由于您提到了升级,因此两种模式都需要针对用户在另一个选项卡中打开页面并尝试使用更高版本(因为它是从服务器下载较新的代码)来打开数据库的情形的另一种方法。假设旧标签页为版本3,新标签页为版本4。

在“每次操作一个连接”的情况下,您会发现版本3上的open()失败,因为另一个选项卡能够升级到版本4。您可以注意到打开失败,VersionError例如,并通知用户他们需要刷新页面。

在每页一个连接的情况下,版本3的连接将阻止另一个选项卡。v4标签可以响应"blocked"请求中的事件,并让用户知道应关闭较早的标签。或者v3选项卡可以响应versionupgrade连接上的事件,并告诉用户需要关闭该事件。或两者。