JavaScript execution mechanism
JavaScript is a single thread language, all the “multithreading” in JavaScript are simulated by a single thread, and this is mainly achieved by the event loop mechanism
Event loop
- Synchronous and asynchronous tasks go to different execution places. Synchronous tasks go to the main thread, while asynchronous tasks go to the Event Table and register functions
- When the specified Event (such as an Ajax Event) completes, the Event Table moves this function to the Event Queue
- When tasks in the main thread are finished, the Event Queue reads the corresponding function and puts it into the main thread for execution
- The above process is repeated over and over again, and the whole process is called the Event Loop
The JS engine has a monitoring process that continuously checks to see if the main thread stack is empty, and if so, goes back to the Event Queue to see if there are any functions waiting to be called.
show demo
let data = {};
$.ajax({
url: www.javascript.com,
data: data,
success: (a)= > {
console.log("Sent successfully!"); }})console.log("Synchronous code execution completed");
Copy the code
- Perform data variable declaration assignment
- When you encounter Ajax and find an asynchronous task, place the task in the Event Table and register the callback function
success
- Continue down
Console. log(" synchronization code execution ended ");
- Ajax event completion, callback function
success
Enter the Event Queue. - The main thread task is finished and read from the Event Queue
success
And perform
setTimeout
The setTimeout function adds the task to the Event Queue after the specified time. In addition, since the tasks of the main thread are executed one by one, if the previous tasks take too long to execute, the tasks in the Event Queue can only wait, so the real delay time of the tasks to be executed by setTimeout may be longer than the specified time.
show demo
setTimeout((a)= > {
task()
},3000)
sleep(10000000)
Copy the code
task
Enter the Event Table and register. The timer starts- perform
sleep
Delta function, very slowly, very slowly, and the timing continues - Three seconds is up. Time event
timeout
Complete,task
Enter the Event Queue, but becausesleep
The execution was too slow. We had to wait until it was finished sleep
At last it was done,task
The Event Queue is finally executed in the main thread
setTimeout(fn, 0) // Specifies that a task should be executed immediately after the main thread execution stack is empty, but this is not possible according to HTML standards. The minimum is 4 millisecondsCopy the code
setInterval
SetInterval is similar to setTimeout except that setInterval executes in a loop. It will place the registered functions in the Event Queue at specified intervals, and if the previous task takes too long, it will also wait. For setInterval(fn, ms), instead of executing fn once every ms seconds, a FN enters the Event Queue every ms seconds. Once setInterval’s fn callback executes longer than the delay time ms, the interval is completely invisible
Definition of more refined tasks
In addition to the generalized synchronous and asynchronous tasks, there are more precise definitions of tasks
- Macro-task: includes the entire code script, setTimeout, and setInterval
- Micro-taks: Promise, process.nexttick
Process. nextTick is similar to the Node version of setTimeout, calling the callback function in the next loop
Different types of tasks enter the corresponding Event Queue. For example, setTimeout and setInterval enter the same Event Queue
The order of the event loop determines the execution order of the JS code. After entering the overall code (macro task), the first loop begins. All of the microtasks generated by this loop are then executed. Then start from the macro task again, find one of the task queues to complete, and then execute all the microtasks.
show demo
setTimeout(function() {
console.log('setTimeout');
})
new Promise(function(resolve) {
console.log('promise');
}).then(function() {
console.log('then');
})
console.log('console');
Copy the code
- This code enters the main thread as a macro task.
- To meet a
setTimeout
Then register its callback function and distribute it to the macro task Event Queue. (The registration process is the same as above and will not be described below) - And then I ran into
Promise
.new Promise
Execute immediately and willthen
The function is distributed to the microtask Event Queue. - If console.log() is encountered, execute immediately.
- The whole script is executed as the first macro task. What are the microtasks? We found that
then
In the microtask Event Queue, execute. - Ok, the first round of the Event loop is over, so let’s start the second round, starting, of course, with the macro task Event Queue. We find the callback function corresponding to setTimeout in the macro task Event Queue and execute it immediately.
- The end.
Check to see if you really understand the js implementation mechanism
Topic 1:
async function async1() {
console.log(1);
const result = await async2();
console.log(3);
}
async function async2() {
console.log(2);
}
Promise.resolve().then((a)= > {
console.log(4);
});
setTimeout((a)= > {
console.log(5);
});
async1();
console.log(6);
Copy the code
Answer:,2,6,4,3,5 [1]
- The whole code goes into the main thread as a macro task
- Two async function declarations are encountered, but ignore them. Then came a Promise that would
then
The function is distributed to the microtask Event Queue - encounter
setTimeout
To register its callback function and distribute it to the macro task Event Queue - Enter the
async1
Function and executes, printing 1 - Down, encounter await and execute
async2
Output 2, await means the code will have to wait console.log(3)
Is in theasync2
The function returns a Promisethen
Function, so it’s distributed to the microtask Event Queue- At this point, the macro task in the main thread is finished, and the micro task is executed in sequence, first 4, then 3
- After the first event loop is complete, the second event loop starts to execute a new synchronization task, and output 5
- The end of the
Topic 2:
console.log('1');
setTimeout(function() {
console.log('2');
process.nextTick(function() {
console.log('3');
})
new Promise(function(resolve) {
console.log('4');
resolve();
}).then(function() {
console.log('5')
})
})
process.nextTick(function() {
console.log('6');
})
new Promise(function(resolve) {
console.log('7');
resolve();
}).then(function() {
console.log('8')
})
setTimeout(function() {
console.log('9');
process.nextTick(function() {
console.log('10');
})
new Promise(function(resolve) {
console.log('11');
resolve();
}).then(function() {
console.log('12')})})Copy the code
Answer: [1,7,6,8, 2,4,3,5, 9,11,10,12]
The first round of event cycle process analysis is as follows:
- The whole script enters the main thread as the first macro task, encountered
console.log
, output 1. - encounter
setTimeout
The callback function is distributed to the macro task Event Queue. Let’s call that thetasetTimeout1
. - encounter
process.nextTick()
, whose callback function is distributed to the microtask Event Queue. We remember toprocess1
. - encounter
Promise
.new Promise
Run it directly and print 7.then
Is distributed to the microtask Event Queue. We remember tothen1
. - Meet again
setTimeout
, whose callback function is distributed to the macro task Event Queue, denoted assetTimeout2
Macro task Event Queue | Microtask Event Queue |
---|---|
setTimeout1 | process1 |
setTimeout2 | then1 |
- The above table shows the situation of each Event Queue at the end of the macro task of the first round of Event loop. At this time, 1 and 7 have been output.
- We found that
process1
andthen1
Two microtasks. - perform
process1
, output 6. - perform
then1
, output 8.
Ok, the first round of event loop is officially over, and the result of this round is output 1,7,6,8. So the second time loop starts with the setTimeout1 macro task:
- First, print 2. And then I ran into
process.nextTick()
, also distributed to the microtask Event Queue, denoted asprocess2
.new Promise
Execute output 4 immediately,then
Also distributed to the microtask Event Queue, denoted asthen2
.
Macro task Event Queue | Microtask Event Queue |
---|---|
setTimeout2 | process2 |
then2 |
- The second event loop macro task ends and we find that there are
process2
andthen2
Two microtasks can be performed. - The output of 3.
- The output of 5.
- The second event loop ends, and the second round outputs 2,4,3,5.
- The third cycle of events begins
setTimeout2
Execute. - So it just prints 9.
- will
process.nextTick()
To the microtask Event Queue. Remember toprocess3
. - Direct execution
new Promise
, output 11. - Distribute THEN to the microtask Event Queue, denoted as
then3
.
Macro task Event Queue | Microtask Event Queue |
---|---|
process3 | |
then3 |
- The third round of event loop macro tasks are completed, and two microtasks are executed
process3
andthen3
. - The output of 10.
- The output of 12.
- The third round of the event loop ends. The third round outputs 9,11,10,12.
The entire code, a total of three times through the event loop, the complete output is 1,7,6,8,2,4,3,5,9,11,10,12. (Please note that the node environment event listening dependency libuv is not exactly the same as the front-end environment, and the output order may be incorrect)
Thank you
This time, thoroughly understand the JavaScript execution mechanism