The distinction between tasks and microtasks is important because IndexedDB transactions commit across tasks, but not microtasks. This is problematic when wrapping IndexedDB code in Promises, because in Firefox (and maybe other browsers), promise resolution does not happen in a microtask, so your transaction will commit.
The solution to this problem is to use a third-party promise implementation that uses microtasks. lie
is one of those libraries, and under the hood it abstracts the microtask problem into another library called immediate
, which uses MutationObserver
to generate microtasks.
That works great, most of the time. But in a Web Worker, MutationObserver
doesn't exist, so that trick won't work. Here's an example of the problem in an easily-runnable GitHub repo. Basically I have this code:
var immediate = require('immediate');
var openRequest = indexedDB.open('firefox-indexeddb-promise-worker-test');
openRequest.onupgradeneeded = function() {
var db = openRequest.result;
var store = db.createObjectStore('whatever', {keyPath: 'id'});
store.put({id: 1});
store.put({id: 2});
store.put({id: 3});
};
function get(tx, id, cb) {
immediate(function () {
var req = tx.objectStore('whatever').get(id);
req.onsuccess = function (e) {
console.log('got', e.target.result);
if (cb) {
cb(null, e.target.result);
}
};
req.onerror = function (e) {
console.error(e.target.error);
if (cb) {
cb(e.target.error);
}
};
});
}
openRequest.onsuccess = function() {
var db = openRequest.result;
var tx = db.transaction('whatever');
tx.oncomplete = function () {
console.log('tx complete');
};
get(tx, 1, function () {
get(tx, 2);
});
};
When I run that normally, it works fine. When I run it in a Web Worker, it fails because the transaction commits when immediate
is called, before the callback runs. This happens in both Chrome and Firefox.
As of now, I've thought of two solutions:
Both of those options are highly unsatsifying. So I ask you, Stack Overflow, do you know of a way to queue microtasks inside of a Web Worker?
short answer: you can't do that in a web worker
long answer: there is no actual microtask api, there are just hacks to try to simulate them. Unfortunately the ones that work best (mutation observer,) mainly have to do with the DOM so they are only available in the main thread not in a web worker. That being said it may make sense for IDB and promises to standardize an official relationship, I'm not sure if there actually is one speced out as promises and IDB are from different groups. There actually might be some traction from browser vendors about doing a real microtask api inside of web workers as most of the objections have to do with accidentally hosing the main thread.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With