Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
521 views
in Technique[技术] by (71.8m points)

javascript - Async operations inside indexeddb cursor

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?

The error I get is:

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

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);
    });
});
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...