1 Event cycle mechanism

Because JS is single threaded, if two threads have conflicting operations on the DOM, to solve the blocking situation, so there is oneThe event loop mechanism.

As javascript code executes, different variables are stored in different locations in memory: heap and stack. There are some objects in the heap. The stack holds some basic type variables and Pointers to objects.

When we call a method, JS generates an execution context corresponding to the method, also called the execution context. The execution environment contains the method’s private scope, the upper scope’s pointer, the method’s parameters, variables, and the scope’s this object.

When a series of methods are called in sequence, because JS is single-threaded, only one method can be executed at a time, so a series of methods are queued on the execution stack.

When a script is executed for the first time, the JS engine parses the code, adds the synchronized code to the stack in the order it is executed, and then executes it from scratch.

If a method is currently executing, js adds the method’s execution environment to the execution stack, and then enters the execution environment to continue executing the code. When the code in this execution environment completes and returns the result, js exits the execution environment and destroys the execution environment, returning to the execution environment of the previous method.

This process is repeated until all the code in the execution stack has been executed.

A method execution adds its execution environment to the execution stack, in which it can call other methods, or even itself, only to add another execution environment to the execution stack. This process can go on indefinitely, unless a stack overflow occurs. The above procedure is all about synchronous code execution.

When the JS engine encounters an asynchronous event, the JS will add the event to the event queue. Instead of executing its callback immediately, it waits for the current stack to complete, immediately processes events in the microtask queue, and then retrieves an event from the macro task queue.

The main thread takes the first event, puts the corresponding callback on the stack, executes the synchronized code, and so on, creating an infinite loop. This is why the process is called an Event Loop.

2 Macro and micro tasks

The different asynchronous tasks are divided into two categories:

  • Macro tasks: overall code,setTimeout(), setInterval()

  • Micro Task: New Promise(). Then callback inside

  • Why macro and micro tasks are distinguished:

Since all tasks are stored in the event queue and are first-in, first-out, but some tasks have a high priority, the concept of microtasks is introduced to ensure the order in which tasks are completed. Js will first complete the macro task, then complete the task in the microtask queue.

Event loop in 3 nodes

Macro task execution order:

1 timer Timer: executes the scheduled setTimeout and setInterval callback functions. 2 Pending callback: Idle,prepare: Only used internally 4 Poll: Retrieves new I/O events, executes I/O callbacks 5 Check: Executes setImmediate () callbacks 6 Close Callbacks socket.on('close',()=>{})Copy the code

The order in which microtasks and macro tasks are executed in node

Node V10 and before:

1 Complete all tasks in a phase. 2 Complete tasks in the nextTick queue. 3 Complete tasks in the microtask queueCopy the code

Node V10 onwards: unified with browser behavior

case

//1 async1 function defined, but not called, so now not output
async function async1() {
  / / 6
  console.log('async1 start')
  / / 7
  await async2()Async2 () in new Promise(() =>{}), async2, print async2
  // then (); then (); // Then ();
  //13 The first microtask, print
  console.log('async1 end')}//2 async2 function defined, but not called, so now not output
async function async2() {
  console.log('async2')}/ / 3 print
console.log('script start')

// 4 setTimeout is a macro task whose priority is lower than that of the micro task. It will be moved to the next macro task queue
setTimeout(function () {
  / / 15 printing
  console.log('setTimeout')},0)

// 5 async1 is executed, so 'async1 start'
async1()

/ / 9
new Promise(function (resolve) {
  // 10 Synchronize code to print
  console.log('Promise1')
  //11. Then is asynchronous, is a microtask, is not executed first
  resolve()
}).then(function () {
  //14 The second microtask is printed. At this point, the microtask queue is cleared, and the next macro task, setTimeout, is enabled
  console.log('Promise2')})//12 Prints, at which point the first macro task has been executed and the microtask queue is cleared
console.log('script end')

/* Print order: script start async1 start async2 Promise1 script end async1 end Promise2 setTimeout */
Copy the code
/ / 1 print
console.log('start')

// 2 macro task, do not execute, move to the next round
//8 Execute the second macro task
setTimeout(() = >{
  / / 9 print
  console.log('children2')
  //10 Instead of adding the. Then callback to the microtask queue, the second macro task is finished, and the microtask queue is emptied.
  Promise.resolve().then(() = >{
    / / 11 print
    console.log('children3')})},0)

/ / 3
new Promise(function (resolve, reject) {
  // 4 Synchronous, print
  console.log('children4')
  // 5 macro task, do not execute, move to the next round
  // 12 Perform the third macro task
  setTimeout(function () {
    / / print 13
    console.log('children5')
    Resolve resolve to change the state of the Promise to fullfilled
    resolve('children6')},0)
  //6 microtasks are not executed.
  SetTimeout is a macro task, so the callback is not added to the microtask queue
  
}).then((res) = >{
  / / 14 to print
  console.log('children7')
  // 15 Macro task execution
  setTimeout(() = >{
    / / 17 print
    console.log(res)
  },0)})/* * start * children4 * the first macro task is finished, then the children4 queue is emptied, but no children2 * the second macro task is finished, then the children4 queue is emptied, * children3 * Tries to execute the third macro task * children5 * children7 * children6 * */
Copy the code
const p = function () {
  / / 1 macro task
  return new Promise((resolve, reject) = > {
    // 2 macro task
    const p1 = new Promise((resolve, reject) = > {
      setTimeout(() = >{
        resolve(1)},0)
      resolve(2)})// 3 Put it into the microtask queue
    p1.then((res) = >{
      console.log(res)/ / 2
    })
    / / 4 printing
    console.log(3)
    resolve(4)})}// add 5 to the microtask queue
p().then((res) = >{
  console.log(res)/ / 4
})
/ / 4 printing
console.log('end')

/*
*3
* end
* 2
* 4
* */
Copy the code