indexeddb游标内的异步操作 [英] Async operations inside indexeddb cursor

查看:288
本文介绍了indexeddb游标内的异步操作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 indexedDB 应许库将 indexedDB API 转换为Promise.

I'm using indexedDB Promised library to convert the indexedDB API to promises.

看起来像我提取完成时,索引数据库事务不再处于活动状态.我猜是要超时了吗?

Looks like by the time my fetch is completed my indexed db transaction is no longer active. I'm guessing it is timing out?

我得到的错误是:

DOMException: Failed to execute 'delete' on 'IDBCursor': The transaction has finished.

我要完成的工作是仅在成功完成获取后才从indexedDB中删除该项目.我了解我可以在提取后创建第二个交易来获取并删除该项目.但是我想知道是否有更好的方法而不进行新交易?我想念什么吗?

What I'm trying to accomplish is to delete the item from indexedDB, only and only if the fetch is completed successfully. I understand that I can create a second transaction after the fetch to get the item and remove it. But I'm wondering if there's a better way without doing a new transaction? Am I missing something?

有人可以向我解释为什么我遇到这个问题吗?

Can anyone explain to me why I'm seeing this problem?

DBHelper.DBPromised.then( db => {
  const store = db.transaction('deferredReviews', 'readwrite').objectStore('deferredReviews');
  const submittedRes = {};
  store.openCursor()
    .then(function submitAndDelete(cursor) {
        if (!cursor) return;
        console.log(cursor.value);

        fetch(`${DBHelper.DATABASE_URL}/reviews`, {
          method: 'POST',
          body: JSON.stringify({
            restaurant_id: cursor.value.restaurant_id,
            name: cursor.value.name,
            createdAt: cursor.value.deferredAt,
            rating: cursor.value.rating,
            comments: cursor.value.comments
          })
        })
        .then(response => {
          if (!response.ok) {
            throw Error(response.statusText);
          }
          return response.json();
        })
        // If response is ok then delete from indexedDB.
        .then(review => {
          if (!review) return new Error('Could not submit');
          if (cursor.value.restaurant_name in submittedRes) {
            submittedRes[cursor.value.restaurant_name] = submittedRes[cursor.value.restaurant_name] + 1;
          } else {
            submittedRes[cursor.value.restaurant_name] = 1;
          }
          cursor.delete();
          return cursor.continue().then(submitAndDelete);
        });
    })
    .then(() => {
      if (Object.keys(submittedRes).length === 0 && submittedRes.constructor === Object) return;
        DBHelper.showDeferredSubmitModal(submittedRes);
    });
});

推荐答案

您不能在indexedDB操作中间执行异步操作.如果IDBTransaction到达JavaScript事件循环的当前迭代结束时未检测到任何未决请求,则它将自动超时.异步操作会引入一个暂停,因此在暂停之后绑定的稍后请求绑定得太晚了,因为到那时事务已超时并结束了.事务的意图是短暂的,因为以读写模式进行的事务可能会在整个过程中锁定对象存储,从而导致严重的阻塞问题.

You cannot do async operations in the middle of indexedDB operations. An IDBTransaction will automatically timeout if it does not detect any pending requests when it reaches the end of the current iteration of the JavaScript event loop. An async operation introduces a pause, so later requests that bind after the pause are bound too late, because by that time the transaction timed out and ended. Transactions are intended to be short lived, because a readwrite mode transaction can potentially lock up an object store for its entire duration, leading to serious blocking issues.

要解决此问题,请在事务之前或之后(而不是在事务中间)执行所有异步工作.如果数据完整性不成问题,或者使用两个单独的事务.

To work around this, do all of your async work either before or after the transaction, not in the middle of it. Or use two separate transactions, if data integrity is not an issue.

这篇关于indexeddb游标内的异步操作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆