preface
Let’s start with a real scenario:
Print out 1 to 1 million on your browser.
Our first response to this requirement looks like this:
for (let i = 0; i < 100 * 10000; i++) {
const div = document.createElement("div");
div.innerText = i;
document.body.append(div);
}
Copy the code
That looks fine, but of course some of you here will say, well, you’ve done a million dom operations here, and the performance cost is pretty bad. That’s a problem, but it’s not the focus of this article.
When we actually run this code, we find that the initial (short) time will not be able to do normal interaction, such as hover, select text, and so on. So why is this happening? No hurry. We’ll take it step by step.
The browser’s rendering mechanism
In Chrome, for example, a TAB exclusively owns a rendering process, and the JavaScript interpretation thread is within the rendering process.
The reason for this is that the screen rendering is based on the DOM structure, and JavaScript has the ability to modify the DOM, so the render action is performed after the JavaScript is executed. In general, the screen is rendered at 60HZ, about 16ms before the human eye is aware of the lag.
So let’s go back to that code
for (let i = 0; i < 100 * 10000; i++) {
}
Copy the code
The conclusion is obvious, this code execution is significantly more than 16ms!!
Event loop mechanism
The Event Loop mechanism is proposed to solve this problem.
To put it simply, we cut a large task into smaller tasks and interleaved the execution of those tasks with the rendering process.
Calculate 1 million (1s) => Screen render
Calculation of 100000 (0.1 s) = = > > screen rendering calculation of 100000 (0.1 s) = = > > screen rendering calculation of 100000 (0.1 s) = >…
I’m not going to post the actual code implementation here, but if you’re interested, you can write it yourself.
Revisit the event loop
After the Event Loop mechanism appeared, JavaScript execution tasks were divided into two types: synchronous tasks and asynchronous tasks. Asynchronous tasks, on the other hand, fall into two categories:
- Macrotask:
The overall code
,The timer
,I/O
- Microtask:
Promise
,MutationObserver
,observer
One thing to note here is that the Promise itself is synchronous code, but its callback then catch is asynchronous
new Promise((res, rej) = > {
res('ok') // Synchronize tasks
}).then((result) = > {
console.log(result) // Microtasks in asynchronous tasks
})
Copy the code
In fact, we might wonder, why these two categories? Why not three or one? It’s a tradeoff strategy. Macro tasks are defined as time-consuming tasks, while microtasks are defined as time-consuming tasks. In actual execution, there are many tasks to be executed, so there will be the priority problem. In fact, the formulation of macro tasks and micro tasks is a compromise, in order to balance the execution time and efficiency.
Priority problem
We just talked about priorities, so let’s talk about that. In general, microtasks perform better than macro tasks. Why in general? Let’s look at this code:
for(let i = 0; i < 10; i++) {
setTimeout(() = > {
console.log('Macro Task Start')
for (let j = 0; j < 10; j++) { microtask(); }})}function microtask() {
return new Promise(async (res) => {
console.log('Microtask Start')
awaitmicrotask(); res(); })}Copy the code
Registering 10 macro tasks => Running the first macro task => Registering 10 microtasks => Registering a microtask during the execution of the microtask => Registering a microtask during the execution of the microtask => Registering a microtask during the execution of the microtask => registering a microtask during the execution of the microtask =>…
This is an infinite loop of microtasks. If the execution of a microtask is superior to that of a macro task, it is impossible for the macro task to trigger the second one because the microtask queue is constantly being pushed.
But in real life, we can see the second macro task start. Why is that? It’s a little strategy Chrome V8 uses to execute the next macro task when there’s too many microtasks.
summary
We introduced Event loops through a small example at the beginning, and there are two types of execution tasks: synchronous tasks and asynchronous tasks. Asynchronous tasks, on the other hand, fall into two categories: macrotasks and microtasks. In general, microtasks perform better than macro tasks. In extreme situations, where microtasks are too many, Chrome V8 executes macro tasks first.