在升级事件中异步更新 IndexedDB

rob*_*rob 5 javascript database asynchronous transactions indexeddb

onupgradeneeded()IndexedDB 事件中,我尝试更新对象存储中的每条记录。为了更新它们,我需要首先执行异步操作,但这会导致升级事务变得不活动,并且我收到错误

Failed to execute 'update' on 'IDBCursor': The transaction is not active.

在下面的代码中,我正在模拟异步操作setTimeout()

let openRequest = indexedDB.open('myDb', 1);

openRequest.onupgradeneeded = function (versionEvent) {
    let db = versionEvent.target['result'];
    let upgradeTransaction = versionEvent.target['transaction'];

    if(versionEvent.oldVersion < 1) {
        let objStore = db.createObjectStore('sample');
        objStore.add('one', '1');
        objStore.add('two', '2');
    }

    if(versionEvent.oldVersion >= 1) {
        let getCursor = upgradeTransaction.objectStore('sample').openCursor();

        getCursor.onsuccess = (e) => {
          let cursor = e.target['result'];
          if (cursor) {
            setTimeout(() => {
              cursor.update(cursor.value + ' updated');
              cursor.continue();
            })
          }
        }
    }
};
Run Code Online (Sandbox Code Playgroud)

https://plnkr.co/edit/DIIzLduZT1dwOEHAdzSf?p=preview

如果你运行这个插件,它将初始化 IndexedDB。然后,如果将版本号增加到2并再次运行,就会出现错误。

如果我的更新依赖于异步操作,如何在升级事件中更新 IndexedDB?

Jos*_*ell 5

你需要一种不同的方法。选项包括:

  • 立即更改架构,但推迟为后续事务添加新数据。
  • 在尝试执行升级之前获取数据。由于获取数据的速度很慢,这可能是不可取的。
  • 仅在需要升级时有条件地获取数据。

后者有两种方法。您可以执行open()没有版本号的操作,检查版本,然后如果版本低于所需版本,则获取/升级。或者您可以在新版本中打开并在upgradeneeded中中止升级(从请求中获取事务并调用abort()它),然后获取数据并重新尝试升级。