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.
  • encountersetTimeoutIs 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.
  • encounternew PromiseIs an asynchronous task,new PromiseDirect execution, outputStart cycleAfter 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.
  • encounterconsole.log(1), for the synchronization task, directly execute, output1.
  • encountersetTimeoutIs 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.
  • encounternew PromiseIs an asynchronous task,new PromiseDirect execution, output6After 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.

  • encountersetTimeoutIs 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 output1and6.
  • Asks if the microtask event queue has any tasks to execute, if yes, isthen1, execute, output7.
  • If the macro task event queue has any tasks to execute, if yes, thensetTimeout1andsetTimeout2.
  • performsetTimeout1First meetconsole.log(2), directly execute, output2.
  • encounternew PromiseIs an asynchronous task,new PromiseDirect execution, output3After 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.

  • encountersetTimeoutIs 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 output7,2,3.
  • Asks if the microtask event queue has any tasks to execute, if yes, isthen2, execute, output4.
  • If the macro task event queue has any tasks to execute, if yes, thensetTimeout2andsetTimeout3.
  • performsetTimeout2First meetconsole.log(8), directly execute, output8.
  • encounternew PromiseIs an asynchronous task,new PromiseDirect execution, output9After 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.

  • encountersetTimeoutIs 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 output4,8,9.
  • Asks if the microtask event queue has any tasks to execute, if yes, isthen3, execute, output10.
  • If the macro task event queue has any tasks to execute, if yes, thensetTimeout3andsetTimeout4.
  • performsetTimeout3First 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 output10,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, thensetTimeout4.
  • performsetTimeout2First 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 output11.
  • 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 output1,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.