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 functionsuccess
  • Continue downConsole. log(" synchronization code execution ended ");
  • Ajax event completion, callback functionsuccessEnter the Event Queue.
  • The main thread task is finished and read from the Event QueuesuccessAnd 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
  • taskEnter the Event Table and register. The timer starts
  • performsleepDelta function, very slowly, very slowly, and the timing continues
  • Three seconds is up. Time eventtimeoutComplete,taskEnter the Event Queue, but becausesleepThe execution was too slow. We had to wait until it was finished
  • sleepAt last it was done,taskThe 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 asetTimeoutThen 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 intoPromise.new PromiseExecute immediately and willthenThe 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 thatthenIn 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 wouldthenThe function is distributed to the microtask Event Queue
  • encountersetTimeoutTo register its callback function and distribute it to the macro task Event Queue
  • Enter theasync1Function and executes, printing 1
  • Down, encounter await and executeasync2Output 2, await means the code will have to wait
  • console.log(3)Is in theasync2The function returns a PromisethenFunction, 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, encounteredconsole.log, output 1.
  • encountersetTimeoutThe callback function is distributed to the macro task Event Queue. Let’s call that thetasetTimeout1.
  • encounterprocess.nextTick(), whose callback function is distributed to the microtask Event Queue. We remember toprocess1.
  • encounterPromise.new PromiseRun it directly and print 7.thenIs distributed to the microtask Event Queue. We remember tothen1.
  • Meet againsetTimeout, 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 thatprocess1andthen1Two microtasks.
  • performprocess1, output 6.
  • performthen1, 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 intoprocess.nextTick(), also distributed to the microtask Event Queue, denoted asprocess2.new PromiseExecute output 4 immediately,thenAlso 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 areprocess2andthen2Two 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 beginssetTimeout2Execute.
  • So it just prints 9.
  • willprocess.nextTick()To the microtask Event Queue. Remember toprocess3.
  • Direct executionnew Promise, output 11.
  • Distribute THEN to the microtask Event Queue, denoted asthen3.
Macro task Event Queue Microtask Event Queue
process3
then3
  • The third round of event loop macro tasks are completed, and two microtasks are executedprocess3andthen3.
  • 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