title: Microtasks inside Web Workers
body: <p>The distinction between tasks and microtasks is important because <a href="https://stackoverflow.com/questions/28388129/inconsistent-interplay-between-indexeddb-transactions-and-promises">IndexedDB transactions commit across tasks, but not microtasks</a>. This is problematic when wrapping IndexedDB code in Promises, because in Firefox (and maybe other browsers), promise resolution does not happen in a microtask, so your transaction will commit.</p>
  
  <p>The solution to this problem is to use a third-party promise implementation that uses microtasks. <a href="https://github.com/calvinmetcalf/lie" rel="nofollow noreferrer"><code>lie</code></a> is one of those libraries, and under the hood it abstracts the microtask problem into another library called <a href="https://github.com/calvinmetcalf/immediate" rel="nofollow noreferrer"><code>immediate</code></a>, which uses <code>MutationObserver</code> to generate microtasks.</p>
  
  <p>That works great, most of the time. But in a Web Worker, <code>MutationObserver</code> doesn't exist, so that trick won't work. <a href="https://github.com/dumbmatter/-firefox-indexeddb-promise-worker-test" rel="nofollow noreferrer">Here's an example of the problem in an easily-runnable GitHub repo.</a> Basically I have this code:</p>
  
  <pre><code>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);
      });
  };
  </code></pre>
  
  <p>When I run that normally, it works fine. When I run it in a Web Worker, it fails because the transaction commits when <code>immediate</code> is called, before the callback runs. This happens in both Chrome and Firefox.</p>
  
  <p>As of now, I've thought of two solutions:</p>
  
  <ol>
  <li>Don't use promises, go back to callback hell</li>
  <li>Use promises with synchronous resolution</li>
  </ol>
  
  <p>Both of those options are highly unsatsifying. So I ask you, Stack Overflow, do you know of a way to queue microtasks inside of a Web Worker?</p>