Writing in the front

The reason for writing this article is that I have been looking at the source code of core-JS for a few days and found the implementation of queueMicrotask. Due to previous projects, the implementation requirements of microtasks were generally completed using asap library. If not, the simple version can be replaced by promise.resolve (). I haven’t been in contact with this API, so I thought I’d take some time to check it out.

compatibility

Generally look at this kind of biased Web standard newapiI’m going to see compatibility firstcaniuseChecked it out, WTF? Unexpectedly search no results. (seeissue)

Then I have to go to MDN to have a look, which looks like the picture below:

Caniuse (caniuse) :

As you can see, the API is relatively new, and if you want to use it directly in your project, it is recommended to import Polyfill or use the ASAP library to implement similar requirements.

Why do we need thisapi?

In terms of the concept of microtasks themselves, we need them when we want a piece of code that doesn’t block the currently executing synchronized code, but also when we want it to execute as fast as possible. (See this article for more details on the concept of microtasks.)

In general, if the business is to write the code, I rarely meet such requirements, the only conceivable situation may exist in some scenarios have performance request for immediate feedback, search, for example, when the input keywords to send an asynchronous request for search information, we may be on the front end to some of the search results, such as sorting or group, However, these operations may not be the highest priority tasks, but they are time-consuming (such as sorting), so we might expect them to be executed later, but as early as possible.

While reading through some well-known frameworks or libraries, I found that there were many cases where authors encountered this requirement, usually addressed through process.nexttick or promise.resolve.

It andsetTimeoutThe difference between?

The essential difference should be in their execution timing, and the difference in execution timing is essentially the difference between microtasks and macro tasks. You can directly open the console and run the following code:

setTimeout(() => {
    console.log('setTimeout');
}, 0);

queueMicrotask(() => {
    console.log('queueMicrotask');
}); 
Copy the code

The result should be:

queueMicrotask
setTimeout
Copy the code

If you’re familiar with Nodejs, it should be similar to process.nextTick.

What are the problems with simulation in other ways?

That was the question that came to my mind at the beginning, which is why do we need this API when we can already simulate microtask execution in other ways? For example, with the following code:

setTimeout(() => {
    console.log('setTimeout');
}, 0);

Promise.resolve().then(() => {
    console.log('queueMicrotask');
}); 
Copy the code

You get the same result as the code above.

Here are some quotes from Explainer: queueMicrotask:

  • We should use the underlying API to perform similar functions directly, rather than using the top-level API to simulate them
  • During the simulation process, there will be some confusion for abnormal conditions, such asPromise.resolveTurns the exception into onerejectedPromise
  • During the simulation, additional objects are created (resulting in some sense of waste), such asPromise.resolveWill return aPromiseInstance object, and directlyqueueMicrotaskWill not be
  • With the exception of microtasks, there are equivalents for all types of asynchronous tasksapiAvailable for use, such as macro tasks,RAF
  • Building on the previous point, the semantics are better, while helping developers understand the differences between these different asynchronous tasks
    • setTimeout(callback, 0)– macro task
    • requestAnimationFrame(callback) – RAF
    • queueMicrotask(callback)Micro tasks –

A potential problem

Because it is a used to assign the task of micro underlying API, in which we are likely to be unlimited access to assign tasks to the queue, the effect is that the micro task queue browser always being not empty state, which will result in control has always been unable to return to the browser for the next event loop, and then it card dead.

You can execute the following code to experience this phenomenon:

function infiniteEnqueue(fn) {
    queueMicrotask(() => infiniteEnqueue(fn))
}

infiniteEnqueue(()=>{})
Copy the code

Running this code will cause the current TAB of the browser to freeze. Use this code with caution. You are advised to open the process management window provided by the browser to forcibly close the window.

About the different implementations of Polyfill

Here is a brief description of MDN and core-JS simulation scheme.

MDN

The polyfill implementation on MDN is simple and crude, and is essentially the same as calling promise.resolve directly, except that an error is caught in a.catch and then thrown.

core-js

Compared with MDN, core-JS is more complex. It considers both NodeJS and Browser, uses linked list data structure to simulate the execution unit of microtask queue, and implements a flush method to represent the execution of all microtask units.

It also implements a notify method that depends on the specific JS runtime environment and API support, Try to flush using process.nextTick, MutationObserver, and Promise.resolve, as well as the basic macro task API, to simulate microtask execution.

reference

  • Explainer: queueMicrotask
  • introduction to microtasks
  • MDN

Pay attention to the public account full stack _101, only talk about technology, not life.


Spare time to take over all kinds of outsourcing projects, interested in private letter.