任务与微任务之间的区别很重要,因为IndexedDB transactions commit across tasks, but not microtasks。将IndexedDB代码包装在Promise中时,这是有问题的,因为在Firefox(也可能是其他浏览器)中,承诺解决方案不会发生在微任务中,因此您的事务将提交。网络工作者内部的微任务
此问题的解决方案是使用使用microtasks的第三方承诺实现。 lie
是其中的一个库,在它的引擎之下,它将microtask问题抽象为另一个名为immediate
的库,该库使用MutationObserver
生成微任务。
这在大多数情况下效果很好。但是在网络工作者中,MutationObserver
不存在,所以这个技巧将不起作用。 Here's an example of the problem in an easily-runnable GitHub repo.基本上我有这个代码:
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);
});
};
当我通常运行,它工作正常。当我在Web Worker中运行它时,它会失败,因为在回调运行之前调用immediate
时事务提交。这发生在Chrome和Firefox中。
截至目前,我想过两种解决方案:
- 不要使用承诺,回去回调地狱
- 使用的承诺与同步分辨率
这两项的选项非常不重要。所以我问你,堆栈溢出,你知道一个在Web Worker中排队microtasks的方法吗?
解析器中同步执行回调的承诺没有听起来那么糟糕。您只需要确保:a)决议本身是异步触发的(或至少在回合结束时); b)您可以信任触发决议的一方 – Bergi
关于“macrotasks”的问题谈话的开头句,但此后是“微型任务”。这是故意的,如果可以,请你解释一下吗? –
@Bergi你知道一个图书馆的行为方式,你描述的方式? – dumbmatter