What is a task queue? What is the execution order of a task queue
# Synchronous vs. Asynchronous
We know that JS is a single threaded language. The so-called “single threaded” means that one task can only be completed at a time. If you have more than one task, you have to queue up, finish the first one, execute the next one, and so on. There are pros and cons to this design! The advantage is that it can improve efficiency, but the disadvantage is that if one task takes a long time, the following tasks have to wait in line, which will delay the execution of the entire program. To solve this problem, the Javascript language divides tasks into two modes of execution: synchronous and asynchronous.
Synchronization mode is that the latter task waits for the end of the previous task, and then executes. The execution order of the program is consistent with the order of the task and synchronized.
In asynchronous mode, each task has one or more callback functions. When the previous task finishes, the callback function is executed instead of the next task on the queue. The latter task is executed without the same callback function as the previous task, so the execution order of the program is not consistent with the order of the tasks.
var t1 = setTimeout(function(){
console.log(2);
},0);
console.log(1);
var t2 = setTimeout(function(){
console.log(3);
},0);
Copy the code
Through the study of these two articles, we can clearly know that the order printed above is 1, 2 and 3. Because setTimeout is an asynchronous task and T1 is registered before T2, this result is printed.
However, it is not clear from the above code that the synchronized task will take precedence over the asynchronous task, because setTimeout has a minimum interval at which console.log(1) can complete. We need to make the synchronized code take longer.
setTimeout(function() {console.log(1);
}, 0);
console.log(2);
let end = Date.now() + 1000*3;
while (Date.now() < end) {}
console.log(3);
end = Date.now() + 1000*3;
while (Date.now() < end) {}
console.log(4);
Copy the code
The console prints the results :2, 3, 4, 1. From the above output, we can determine that the asynchronous code is executed after all the synchronous code has been executed.
Macro tasks versus microtasks
A macro task is a macro task that is executed every time on the execution stack (including fetching an event callback from the event queue and putting it on the execution stack).
What is a microtask? A microtask is a task that is executed immediately after the current task is completed. That is, after the current task, before the next task, before rendering.
So it will respond faster than setTimeout (which is task) because you don't have to wait to render. That is, after a macroTask is executed, all microtasks generated during its execution are executed (before rendering).
NextTick Common macro task setTimeout setInterval I/O script
Let’s look at the code below
setTimeout(function(){
console.log(1);
},0);
new Promise(function(resolve){
console.log(2);
resolve();
console.log(3);
}).then(function(){
console.log(4);
});
console.log(5);
setTimeout(function(){
console.log(6);
},0);
console.log(7);
Copy the code
The console prints results 2, 3, 5, 7, 4, 1, 6. What explains this result? First of all, we know that the synchronous task must take precedence over the asynchronous task, setTimeout the asynchronous task must be executed after the synchronization task is finished, the scheduled time is the same, the early registration is executed first, so the 1 must precede the 6, the reason why the 2 is printed first is because the promise is internally a synchronization task. Resolve (.then) is a microtask that will be executed only after the current macro task is completed, so put it in the microtask queue at this time. Continue to print down 3, 5, 7 Synchronous task execution ends here start to execute the current microtask queue so print 4, finally execute asynchronous task print 1, 6. Microtasks are special asynchronous tasks, which differ from asynchronous tasks in that normal tasks are appending to the next round of event loop, while microtasks are appending to the current round of event loop. This means that microtasks must be executed before normal tasks.
Combined with the above examples, we will understand the JS operation mechanism
Operation mechanism
In the event loop, each loop operation is called a tick. The task processing model of each tick is relatively complex, but the key steps are as follows:
- Execute a macro task (if not in the stack, get from the event queue)
- If a microtask is encountered during execution, it is added to the task queue of the microtask
- All microtasks in the current microtask queue are executed immediately after the macro task is executed (in sequence).
- The current macro task is finished, the rendering is checked, and the GUI thread takes over the rendering
- After rendering, the JS thread continues to take over and starts the next macro task (fetch from the event queue)