How it differs from the browser environment

The Node environment and the browser environment display the same event loop state. The only difference is that:

  1. The JS engine has a monitoring process that continuously checks that the main thread is empty. If it is empty, it checks the callback queue to see if there are any functions waiting to be called. (There are only two queues: macro task and micro task)
  2. Node is implemented by libuv engine. The JS code we write is analyzed by V8 engine to call the corresponding nodeAPI, which is finally driven by Libuv engine and has its own model in libuv engine. Different events are placed in different queues waiting for the main thread to execute. (There are 6 macro task queues and 1 microtask queue in the model)

The stages of the Node event cycle

// Event models in the Libuv engine, with some description added after each model┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐ ┌ ─ > │ timers │ setTimeout/callback │ setInterval └ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┬ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┘ │ left │ ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┴ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐ │ │ pending callbacks │ processing network, flow, TCP error correction │ └ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┬ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┘ │ left │ ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┴ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐ │ │ idle, Prepare │ only used inside the node │ └ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┬ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┘ │ left ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐ │ ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┴ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐ │ incoming: │ │ ├ ─ poll │ I/O queue <------│ connections, │ └ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┬ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┘ │ data, Etc. │ │ left └ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┘ │ ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┴ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐ │ │ check setImmediate callback │ │ stored └ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┬ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┘ │ left │ ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┴ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐ └ ─ ─ ┤ close callbacks │ closed callback (socket) on ('close')... └ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┘Copy the code

Several stages in the Node event cycle

A more detailed description of the official event-loop-timers-and-Nexttick

  1. times: This phase executes the callback function in the timer queue (setTimeoutsetInterval )
  2. pending callback: This phase performs almost all callbacks (network, stream, TCP errors…) . In addition,closeCallback, timer callback,setImmediateCall back the three defined phases
  3. Idle, prepare: This phase is for internal use only.
  4. Poll: Waiting for new I/O events, node blocks here in special cases, check whether the timer is on time (entry)
  5. check:setImmediate()The callback is executed during this phase
  6. close callbacks: e.g.socket.on('close', ...)
  7. process.nextTick.then()Is executed during a phase switch in the event loop

Having said a bunch of concepts, let’s look at this code

(function test() {
  setTimeout(function () { console.log(4)},0);
  new Promise(function (resolve, reject) {
    console.log(1);
    for (var i = 0; i < 10000; i++) {
      i == 9999 && resolve();
    }
    console.log(2);
  }).then(function () {
    console.log(5);
  });
  console.log(3); }) ();// This code is familiar
// the final result 1,2,3,5,4 is the same as in the browser
Copy the code

Let’s do something a little more difficult

And the previous blog from an implementation problem, understand the browser JS implementation mechanism in the code (⊙﹏⊙)b

console.log(1)

setTimeout((a)= > {
  console.log(2)
  new Promise(resolve= > {
    console.log(4)
    resolve()
  }).then((a)= > {
    console.log(5)})})new Promise(resolve= > {
  console.log(7)
  resolve()
}).then((a)= > {
  console.log(8)
})

setTimeout((a)= > {
  console.log(9)
  new Promise(resolve= > {
    console.log(11)
    resolve()
  }).then((a)= > {
    console.log(12)})})// Result in browser: 1, 7, 8, 2, 4, 5, 9, 11, 12
// Results in Node: 1, 7, 8, 2, 4, 9, 11, 5, 12
Copy the code

The analysis is as follows:

  1. In the browsermacro taskWhen the execution is complete, loop againMacro taskTasks in MICRO are processed first before the callback queue of So the results are: 1, 7, 8, 2, 4, 5, 9, 11, 12
  2. inNodeThere are six macro task queues that the event loop enters firstpollPhase. Enter thepollCheck whether there is a set after phasetimers(timer) Time is up, if one or more times are up,Event LoopWill skip the normal circular process and directly fromtimersThe timers callback stage executes and the timers callback queue is executed only when thetimersPhase after the callback queue completes execution. To take it to the next level. Is that whysetTimeoutThere are.then, and was not immediately executed for reasons whentimersPhase is triggered during the process of switching to the next phase after the callback queue is completedMicro tasks(process.nextTick.then). Between phases and phases.

Let’s do one more foundation problem

setTimeout(function () {
  console.log('setTimeout')}); setImmediate(function () {
  console.log('setImmediate')});Copy the code

Result :(setTimeout, setImmediate)

Why is that? The default minimum time of setTimeout in the standard is 4ms. If the time for starting node and executing node code is less than 4ms, then the code will be transmitted to libuv engine after parsing. At first, the poll stage will be entered to check whether the set time has reached the cut-off point. If the interval is less than 4ms, then the check phase is triggered, and setImmediate triggers setTimeout. SetImmediate if it takes longer than or equal to 4ms to start node and run the node code, setTimeout is followed by setImmediate

Evolution on the basis of the classic problem

setImmediate((a)= > {
  console.log('setImmediate1')
  setTimeout((a)= > {
    console.log('setTimeout1')},0);
})
setTimeout((a)= >{
  process.nextTick((a)= >console.log('nextTick'))
  console.log('setTimeout2')
  setImmediate((a)= >{
    console.log('setImmediate2')})},0);
Copy the code

Two cases (where nextTick is executed: it is executed during queue switch)

  1. ifsetImmediateTo perform:SetImmediate1, setTimeout2, setTimeout1, nextTick, setImmediate2
  2. ifsetTimeoutTo perform:SetTimeout2, nextTick, setImmediate1, setImmediate2, setTimeout1

The literal translation of setImmediate and Process. nextTick

  1. The meaning of Immediate execution is actually fixed atcheckPhases are executed. The meaning of this literal translation andprocess.nextTickIs the best match.
  2. The Node developers are aware of the confusion and say they will not switch the names of the two methods – because so many Node applications use the two methods, the benefits of switching the names are insignificant compared to the impact.

What’s the use of knowing this stuff?

  1. Allows us to have a clear view of the order in which asynchronous code is executed (important)
  2. Postponing the Task
  3. The interview

conclusion

These concepts are far more important than you might think

  1. whynew PromiseThe first argument is executed synchronously, right?Learn Promise && Make Promise easy
  2. The browserIn theJSWhat does the enforcement mechanism look like?From an implementation problem, understand the browser JS execution mechanism

P: This blog may wish to express that the concept is much more important than imagined