Skip to content

Instantly share code, notes, and snippets.

@robertknight
Last active March 4, 2022 05:59
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save robertknight/462d16b46a438ab67e29301861f5d55f to your computer and use it in GitHub Desktop.
Save robertknight/462d16b46a438ab67e29301861f5d55f to your computer and use it in GitHub Desktop.
Promises + IndexedDB Test

This gist demonstrates a problem with IndexedDB & Promises in Firefox which makes using IndexedDB very unergonomic in some cases in Firefox.

The test below reads, updates & writes a counter value to an IndexedDB database 10 times in the same transaction and then prints the result. To make the code easier to read, it uses async + await, which requires converting the IndexedDB requests (IDBRequest objects) to promises with a simple helper.

In Chrome, multiple promise callbacks can be executed with auto-committing an IDB transaction, allowing read-modify-write steps to work. In Firefox however, the IDB transaction gets auto-committed before the promise callback is fired, which means that read-modify-write operations have to use callbacks rather than promises.

<html>
<head>
</head>
<body>
<script>
function promiseReq(req) {
return new Promise((resolve, reject) => {
req.onsuccess = () => resolve(req.result);
req.onerror = () => reject(req.error);
});
}
async function test() {
// Open database.
let dbReq = indexedDB.open('test', 2);
dbReq.onupgradeneeded = () => {
let db = dbReq.result;
db.createObjectStore('counters');
};
let db = await promiseReq(dbReq);
// Increment a counter 10 times in the same transaction.
let tx = db.transaction('counters', 'readwrite');
let store = tx.objectStore('counters');
for (let i=0; i < 10; i++) {
let val = await promiseReq(store.get('counter'));
if (typeof val !== 'number') {
val = 0;
}
val += 1;
await promiseReq(store.put(val, 'counter'));
}
// Output the final value.
let finalVal = await promiseReq(store.get('counter'));
console.log('Final value', finalVal);
}
console.log('Starting test');
test().catch(err => console.error('Test failed', err));
</script>
</body>
</html>
@birtles
Copy link

birtles commented Dec 5, 2019

This has been fixed as of Firefox 60 (released 2018-05-09).

@robertknight
Copy link
Author

Thanks for the update @birtles 🙂

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment