The introduction
Let’s start with a question, and if you get it right, you can close the page.
What is the result of executing the following code?
SetTimeout (function() {console.log(' I am the timer ')},2000); New Promise(function(resolve) {console.log(' start loop '); for (var i = 0; i < 1000; i++) { i == 999 && resolve(); }}). Then (function() {console.log(' loop ended ')}); Console. log(' code execution ends ');Copy the code
Refer to the answer
Start loop code execution ends loop ends I'm the timerCopy the code
Single-threaded JavaScript
Single-threaded means you can only do one thing at a time. Multithreading means you can do many things at the same time.
JavaScript is single-threaded. One thread adds content to a DOM node, and the other thread removes that node. So JavaScript can only be single-threaded.
Some might say that in HTML5 you can use new Worker(xxx.js) to create multiple threads in JavaScript. However, the child thread is completely controlled by the main thread and cannot manipulate the DOM. So JavaScript is still single threaded.
Synchronous and asynchronous tasks in JavaScript
Single threading means that all tasks need to be queued until the first one is finished before the next one can be executed. This is a synchronization task in JavaScript.
But the synchronization task has a big weakness, if a task executes for a long time before hasn’t ended, the next task will not be able to perform, for example, page rendering a region need to use Ajax to request data in the process, such as data, the request for a long time is less than the next task will not be able to perform, also said other area cannot render a page. There are JavaScript asynchronous tasks to address this shortcoming.
Asynchronous tasks can be executed separately, not after the previous task has finished. But the asynchronous task will wait there until there are no more tasks in the thread. The callback function of the asynchronous task is called to execute.
All right, let’s go straight to the picture above. Let’s talk about how synchronous and asynchronous tasks are performed in JavaScript.
- Synchronous and asynchronous tasks go to different execution “places”, synchronous tasks go to the main thread, asynchronous tasks go to the Event Table and register callback functions.
- This callback function is added to the Event Queue when the asynchronous task is finished.
- After the execution of tasks in the main thread is completed, the Event Queue will ask if there are any tasks to be executed. If there are any tasks, it will enter the task execution stack in the order of first add first execute, and then continue to execute according to the previous steps.
- This process is repeated over and over again, known as an Event Loop.
Here’s an example to see if you understand
setTimeout(function() {
console.log(1);
}, 2000)
console.log(2);
setTimeout(function() {
console.log(3);
}, 1000)
console.log(4);
Copy the code
Refer to the answer
2,4,3,1
Copy the code
If you answered the above example correctly, go back to the original question:
SetTimeout (function() {console.log(' I am the timer ')},1000); New Promise(function(resolve) {console.log(' start loop '); for (var i = 0; i < 1000; i++) { i == 999 && resolve(); }}). Then (function() {console.log(' loop ended ')}); Console. log(' code execution ends ');Copy the code
Analyze the above content. You might get the following answer
Start loop code execution ends I'm the timer loop endsCopy the code
Of course the answer is wrong, at which point you start to think the above is wrong.
Don’t worry, there are also macro and micro tasks for asynchronous JavaScript tasks, which are covered below.
Macro and micro tasks in JavaScript
- Macro-task: Whole code script, setTimeout, setInterval, setImmediate
- Micro-task :Promise, process.nexttick
Macro and micro tasks are a further refinement of JavaScript asynchronous tasks. Asynchronous event queues are divided into macro task event queues and micro task event queues.
Drive directly above. To illustrate how macro and micro tasks are performed in JavaScript.
- Synchronous and asynchronous tasks go to different execution “places”, synchronous to the main thread, asynchronous to the event list and register callback functions.
- After the asynchronous task is executed, determine whether the asynchronous task is a macro task or a micro task, add the callback function of the macro task to the macro task event queue, and add the callback function of the micro task to the micro task event queue.
- After the tasks in the main thread are completed.
- First go to the microtask event queue and ask if there are any tasks to be executed. If there are any tasks, then go to the task execution stack in the order of first add first execute.
- If not, go to the macro task event queue and ask if there are any tasks to execute. If so, the task execution stack is added first.
- If not, the mission is complete.
- This process is repeated over and over again, known as an Event Loop.
Let’s analyze the original question as follows:
SetTimeout (function() {console.log(' I am the timer ')},1000); New Promise(function(resolve) {console.log(' start loop '); for (var i = 0; i < 1000; i++) { i == 999 && resolve(); }}). Then (function() {console.log(' loop ended ')}); Console. log(' code execution ends ');Copy the code
- The whole script enters the main thread as the first macro task.
- encounter
setTimeout
Is an asynchronous task. After the task is executed, it is judged to be a macro task. Therefore, the callback function is added to the macro task event queue, which is denoted assetTimeout
. - encounter
new Promise
Is an asynchronous task,new Promise
Direct execution, outputStart cycle
After the task is executed, it is judged to be a micro-task, so the then method is bound
The specified callback function is added to the microtask event queue, which we denote as then.
-
If console.log(‘ code execution ends ‘) is encountered, execute directly for synchronization task, and output code execution ends.
-
When the tasks are all executed, the microtask event queue is asked if there are any tasks to be executed. If so, then, the execution, output loop ends.
-
The macro task event queue is asked if there is any task to execute. Yes, setTimeout, execute, output I am timer.
Macro task Event Queue Microtask Event Queue setTimeout then
The final output is
Start loop code execution ends loop ends I'm the timerCopy the code
It matches the correct answer. It seems that the above JavaScript execution mechanism is correct. Let’s take a look at another complex example to get a thorough understanding of JavaScript execution.
Let’s make a summary of examples
console.log('1');
setTimeout(function() {
console.log('2');
new Promise(function(resolve) {
console.log('3');
resolve();
}).then(function() {
console.log('4')
})
setTimeout(function(){
console.log('5')
})
})
new Promise(function(resolve) {
console.log('6');
resolve();
}).then(function() {
console.log('7')
})
setTimeout(function() {
console.log('8');
new Promise(function(resolve) {
console.log('9');
resolve();
}).then(function() {
console.log('10')
})
setTimeout(function(){
console.log('11')
})
})
Copy the code
- The whole script enters the main thread as the first macro task.
- encounter
console.log(1)
, for the synchronization task, directly execute, output1
. - encounter
setTimeout
Is an asynchronous task. After the task is executed, it is judged to be a macro task. Therefore, the callback function is added to the macro task event queue, which is denoted assetTimeout1
. - encounter
new Promise
Is an asynchronous task,new Promise
Direct execution, output6
After the task is executed, it is judged to be a micro-task, so the then method is bound
The specified callback function is added to the microtask event queue, which we’ll call then1.
- encounter
setTimeout
Is an asynchronous task. After the task is executed, it is judged to be a macro task. Therefore, the callback function is added to the macro task event queue, which is denoted assetTimeout2
.
Macro task Event Queue | Microtask Event Queue |
---|---|
setTimeout1 | then1 |
setTimeout2 |
- The above table shows each Event Queue at the end of the first Event loop macro task, which has been output
1
and6
. - Asks if the microtask event queue has any tasks to execute, if yes, is
then1
, execute, output7
. - If the macro task event queue has any tasks to execute, if yes, then
setTimeout1
andsetTimeout2
. - perform
setTimeout1
First meetconsole.log(2)
, directly execute, output2
. - encounter
new Promise
Is an asynchronous task,new Promise
Direct execution, output3
After the task is executed, it is judged to be a micro-task, so the then method is bound
The specified callback function is added to the microtask event queue, which we’ll call then2.
- encounter
setTimeout
Is an asynchronous task. After the task is executed, it is judged to be a macro task. Therefore, the callback function is added to the macro task event queue, which is denoted assetTimeout3
.
Macro task Event Queue | Microtask Event Queue |
---|---|
setTimeout2 | then2 |
setTimeout3 |
- The above table shows the situation of each Event Queue at the end of the second Event loop macro task, which has been output
7
,2
,3
. - Asks if the microtask event queue has any tasks to execute, if yes, is
then2
, execute, output4
. - If the macro task event queue has any tasks to execute, if yes, then
setTimeout2
andsetTimeout3
. - perform
setTimeout2
First meetconsole.log(8)
, directly execute, output8
. - encounter
new Promise
Is an asynchronous task,new Promise
Direct execution, output9
After the task is executed, it is judged to be a micro-task, so the then method is bound
The specified callback function is added to the microtask event queue, which we’ll call then3.
- encounter
setTimeout
Is an asynchronous task. After the task is executed, it is judged to be a macro task. Therefore, the callback function is added to the macro task event queue, which is denoted assetTimeout4
.
Macro task Event Queue | Microtask Event Queue |
---|---|
setTimeout3 | then3 |
setTimeout4 |
- The above table shows the situation of each Event Queue at the end of the macro task of the third round of Event loop, which has been output
4
,8
,9
. - Asks if the microtask event queue has any tasks to execute, if yes, is
then3
, execute, output10
. - If the macro task event queue has any tasks to execute, if yes, then
setTimeout3
andsetTimeout4
. - perform
setTimeout3
First meetconsole.log(5)
, directly execute, output5
.
Macro task Event Queue | Microtask Event Queue |
---|---|
setTimeout4 |
- The above table shows the situation of each Event Queue at the end of the macro task of the fourth or third round of the Event cycle, which has been output
10
,5
. - The microtask event queue is asked if there are any tasks to execute.
- If the macro task event queue has any tasks to execute, if yes, then
setTimeout4
. - perform
setTimeout2
First meetconsole.log(11)
, directly execute, output11
Macro task Event Queue | Microtask Event Queue |
---|---|
- The above table shows the situation of each Event Queue at the end of the macro task of the fifth Event loop, which has been output
11
. - The microtask event queue is asked if there are any tasks to execute.
- The macro task event queue is asked if there are any tasks to execute.
- The mission is complete.
- The final output
1
,6
,7
,2
,3
,4
,8
,9
,10
,5
,11
Print it out on Chrome and the comparison is correct.
If the
setTimeout(function(){
console.log('5')
})
Copy the code
to
setTimeout(function(){
console.log('5')
},2000)
Copy the code
What would be the result? Let’s do the reasoning above. Just to remind you, asynchronous tasks are added to the event queue after they are executed.