Reputation: 724
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);
});
});
Upvotes: 4
Views: 1869
Reputation: 18720
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.
Upvotes: 7