Микротовары внутри веб-работников

Различие между задачами и микротомами важно, потому что транзакции IndexedDB совершают задачи, но не микротовары. Это проблематично при обертке кода IndexedDB в Promises, потому что в Firefox (и, возможно, в других браузерах) обещание не выполняется в микрозадаче, поэтому транзакция будет зафиксирована.

Решение этой проблемы заключается в использовании стороннего обещания, в котором используются микротовары. lie является одной из этих библиотек, и под капотом он абстрагирует проблему микрозадачи в другой библиотеке под названием immediate, который использует MutationObserver для создания микротоков.

Это работает отлично, большую часть времени. Но в Web Worker MutationObserver не существует, так что трюк не будет работать. Вот пример проблемы в легко исполняемом репозитории GitHub. В основном у меня есть этот код:

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.

На данный момент я подумал о двух решениях:

  • Не используйте Promises, вернитесь к обратному аду.
  • Используйте promises с синхронным разрешением

Оба эти параметра сильно не распознаются. Итак, я спрашиваю вас, "Переполнение стека", знаете ли вы, как настроить очередь на микрозадания внутри веб-рабочего?

Ответ 1

короткий ответ: вы не можете сделать это в веб-работнике

длинный ответ: нет реальной микротаски api, есть только хаки, чтобы попытаться имитировать их. К сожалению, те, которые работают лучше всего (наблюдатель мутаций), в основном связаны с DOM, поэтому они доступны только в основном потоке, а не в веб-работнике. При этом для IDB и promises может быть разумно стандартизировать официальные отношения, я не уверен, действительно ли один из них представлен как promises, а IDB - из разных групп. На самом деле может быть какая-то тяга к поставщикам браузеров о том, как делать настоящую microtask api внутри веб-работников, поскольку большинство возражений связано с случайным ходом основного потока.