任务和微任务之间的区别很重要,因为
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中运行它时,它会失败,因为事务在立即被调用之前提交,在回调运行之前. Chrome和Firefox都会发生这种情况.
截至目前,我已经想到了两个解决方案:
>不要使用承诺,回到回调地狱
>使用具有同步分辨率的承诺
这两个选项都是非常不合格的.所以我问你,Stack Overflow,你知道一个在Web Worker里排队的方法吗?
解决方法
简短的答案:你不能在网络工作者中做到这一点
长的答案:没有实际的微型api,只有黑客试图模拟它们.不幸的是,最好的(突变观察者)主要与DOM有关,因此它们只能在不在网络工作者中的主线程中使用.据说这可能对IDB有意义,并承诺规范官方关系,我不知道是否有实际上是作为承诺而被指定为IDB的来自不同的组织.实际上,浏览器供应商可能会在网络工作人员之间做一个真正的微型api,因为大多数反对意见都与意外地使用主线程有关.