Thursday 9 January 2020

How to queue a microtask if the browser doesn't support native Promises?

It's better to write code that doesn't rely on the timing of immediate callbacks (like microtasks vs macrotasks), but let's put that aside for the moment.

setTimeout queues a macrotask, which, at a minimum, waits to start until all microtasks (and microtasks that they spawn) finish. Here's an example:

console.log('Macrotask queued');
setTimeout(function() {
  console.log('Macrotask running');
});
Promise.resolve()
  .then(function() {
    console.log('Microtask running');
  });
console.log('Microtask queued');
console.log('Last line of script');

The behavior of a .then on a resolved Promise is fundamentally different from the behavior of an immediate setTimeout callback - the Promise .then will run first, even if the setTimeout was queued first. But only modern browsers support Promises. How can the special functionality of a microtask be properly polyfilled if Promise doesn't exist?

If you try to imitate a .then's microtask by using setTimeout, you'll be queuing a macrotask, not a microtask, so the badly-polyfilled .then won't run at the right time if a macrotask is already queued.

There's a solution using MutationObserver, but it looks ugly, and isn't what MutationObserver is for. Also, MutationObserver is not supported on IE10 and earlier. If one wants to queue a microtask in an environment that doesn't natively support Promises, are there any better alternatives?

(I'm not actually trying to support IE10 - this is just a theoretical exercise on how microtasks can be queued without Promises)



from How to queue a microtask if the browser doesn't support native Promises?

No comments:

Post a Comment