Web Workers中的Microtasks

时间:2017-03-07 23:58:08

标签: javascript promise indexeddb web-worker

任务和微任务之间的区别非常重要,因为IndexedDB transactions commit across tasks, but not microtasks。在Promises中包装IndexedDB代码时会出现问题,因为在Firefox(可能还有其他浏览器)中,微任务中不会发生协议解析,因此您的事务将提交。

此问题的解决方案是使用使用微任务的第三方承诺实现。 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中。

截至目前,我已经想到了两个解决方案:

  1. 不要使用承诺,回到地狱回调
  2. 使用具有同步解析的承诺
  3. 这两个选项都非常不稳定。所以我问你,Stack Overflow,你知道一种在Web Worker中排队微任务的方法吗?

1 个答案:

答案 0 :(得分:5)

简短回答:你不能在网络工作者那里做到这一点

答案很长:没有实际的微任务api,只有黑客才能尝试模拟它们。不幸的是,那些效果最好的(变异观察者)主要与DOM有关,因此它们仅在主要线程中可用,而不在Web工作者中。据说这可能对IDB有意义,并承诺将官方关系标准化,我不确定是否实际上有一个作为承诺而且IDB来自不同的团体。浏览器供应商实际上可能会有一些关于在Web工作者中进行真正的微任务api的牵引力,因为大多数异议都与意外泄漏主线程有关。