【发布时间】:2017-03-07 23:58:07
【问题描述】:
任务和微任务之间的区别很重要,因为IndexedDB transactions commit across tasks, but not microtasks。这在 Promises 中包装 IndexedDB 代码时会出现问题,因为在 Firefox(可能还有其他浏览器)中,承诺解析不会发生在微任务中,因此您的事务将提交。
解决这个问题的方法是使用使用微任务的第三方 Promise 实现。 lie 就是其中一个库,在底层,它将微任务问题抽象到另一个名为 immediate 的库中,该库使用 MutationObserver 生成微任务。
这在大多数情况下都很好用。但是在 Web Worker 中,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 中都会发生。
到目前为止,我已经想到了两种解决方案:
- 不要使用承诺,回到回调地狱
- 使用具有同步解析的承诺
这两个选项都非常不令人满意。所以我问你,Stack Overflow,你知道在 Web Worker 中排队微任务的方法吗?
【问题讨论】:
-
在解析器中同步执行回调的承诺并不像听起来那么糟糕。您只需要确保 a) 决议本身是异步触发的(或至少在回合结束时)并且 b) 您可以信任触发决议的一方
-
问题的开始句谈论“宏任务”,但随后是“微任务”。这是故意的吗?如果是,请解释一下?
-
@Bergi 你知道一个库的行为方式和你描述的一样吗?
-
@Roamer-1888 这是一个错字,谢谢。我相信“任务”和“宏任务”在这种情况下是同义词,而“微任务”是不同的。
-
@dumbmatter I had written one myself,但我想您可以使用任何允许您提供自己的调度程序的方法
标签: javascript promise indexeddb web-worker