The last time you and I masturbated and PromiseA+, I’m sure all you want is watermelon cola……

Watermelon cola! It was a Promise!

Eh, wake up, today we move a small bench, listen to me talk about JS more interesting event ring, before understanding the event ring, let’s first understand a few basic concepts.

The Stack (Stack)

A stack is a last in, first out (LIFO) collection of data, with new elements added or to be removed stored at the end of the stack, called the top, and the other end called the bottom of the stack. In the stack, the new elements are near the top of the stack, and the old elements are near the bottom of the stack

Feeling is not well understood, we, for example, there is a table tennis box, for example, we kept the ball in the box in the table tennis, then put in the first table tennis must be in the bottom, finally it must be in the top, so if we want to put the ball out whether must be from top to bottom in turn to take out, The model is last-in, first-out, where the last ball we put into the box comes out first.

The concept of stack is actually very important in our JS, we all know that js is a single-threaded language, so he single-threaded where, in his main thread, also known as the execution context, this execution context is the stack space, let’s look at a piece of code:

 console.log('1');
 function a(){
    console.log('2');
    function b(){
        console.log('3')
    }
    b()
 }
 a()
 
Copy the code

We know that when the function is executed, it will put the function into our execution context, and when the function is finished, it will pop up the execution stack, so according to this principle, we can know how the code is running

  1. First of all, we’re going to have a global context when our code is executing, and when the code is running, the global context is executing at the bottom of the stack
  2. We meetconsole.log('1'), this function goes on the stack when it’s called, and when this sentence is done and we get to the next lineconsoleThe function goes off the stack, and there is still only the global context in the stack
  3. And then we run the code, and the thing to notice here is that none of the function declarations that we encounter are going to be on the execution stack, they’re only going to be on the execution stack when our function is called, and that’s exactly what the name of our execution stack is, and then we encountera();So this is where our a function goes to the stack, and then it goes to usa, where our function execution stack should beGlobal context -- a
  4. And then I runconsole.log('2')Execute the stack toGlobal context -- a -- consoleAnd then ourconsoleAfter running, we perform stack restore toGlobal context -- a
  5. And then we metb(); thenbGo to our execution stack,Global context -- a -- b.
  6. And then go inside the b function and executeconsole.log('3')Execute stack isGlobal context -- a -- b -- consoleAfter the execution is complete, reply toGlobal context -- a -- b
  7. And then ourbThe function is done executing, and then it gets popped off the stack, and the stack becomesGlobal context -- a
  8. And then ouraThe function is done executing, and then it gets popped off the stack, and the stack becomesGlobal context
  9. Our global context is then pushed out when our browser is closed

This is how our execution context works, isn’t it a lot clearer

From the execution context above we can see several characteristics:

  • The execution context is single threaded
  • The execution context is synchronous code execution
  • When a function is called, it enters the execution context
  • The code runs in a global context and is only pushed off the stack when the browser is closed

Queue

A queue is a collection of data that follows a first in, first out (FIFO), where new items are added to the end of the queue and old items are removed from the head of the queue.

And here we can see that the difference between a queue and a stack is that the stack is last in, first out like a ping-pong box, and the queue is first in, first out, which means that the first one in is the first one out. We also, for example, the queue is like we line up past security, first came to the first person in line, later then in line behind, and then will subject from the head end of team security checks, check out one will release a person, whether such a team is a process of first in first out.

We will mention two concepts: macro task and Micro task.

Task queue

Js event execution is divided into macro tasks and micro tasks

  • Hongren service is mainly composed ofscript(Global task),setTimeoutsetIntervalsetImmediate, I/O, UI rendering
  • Microtasks are mainlyprocess.nextTick.Promise.then.Object.observer.MutationObserver.

Browser event loop

Js code is executed in the process of task if you meet the above code, will first put these code correction in the corresponding task queue, and then continue to execute a function to be executed in the context of the main thread code to know after all completed, will go to the micro related tasks in the task queue, micro task queue to empty, Take the task from the macro queue and place it in the execution context, then continue the loop.

  1. Execute the code, put the macro kernel into the macro kernel queue, put the micro task into the micro task queue, and put the execution context when performing other functions
  2. After all execution is complete in the execution context, the microtask queue is executed
  3. After the execution of the microtask queue is completed, the first item is taken out from the macro benevolence queue and executed in the execution context
  4. And then we just keep going through steps 1 to 3, which is 1Browser environmentIn theJs event loop
// Let's look at an interview questionsetTimeout(function () {
      console.log(1);
    }, 0);
    
    Promise.resolve(function () {
      console.log(2);
    })
    
    new Promise(function(resolve) { console.log(3); }); console.log(4); // What is the output of the above code?Copy the code

Think think think think think ~~~

The correct answer is 3, 4, 1. Is that what you thought? Let’s look at the flow of the code

/ / meetsetThe Timeout willsetThe Timeout callback is placed in the macroserver queuesetTimeout(function() { console.log(1); }, 0); // I met a promise, but I didn'tthenMethod callback so this code will go into our current execution context during execution and then we'll push promise.resolve (function() { console.log(2); }) // We encountered a new Promise, and I don't know if you remember from our last article we talked about promises. One of the rules is that when you initialize a Promise, the constructor inside the Promise will execute immediately, so it immediately prints a 3, So this 3 is the first new Promisefunction(resolve) { console.log(3); }); // Then input the second output 4. When the code is finished, it goes back to the microtask queue and finds that the microtask queue is empty. Then it goes to the macro task queue and finds that there is one we just put insetThe Timeout callback is used to retrieve the task and execute it, so 1 console.log(4) is immediately printed;Copy the code

See the above explanation, we all understand, is not straight call simple ~

Let’s take a look at the event execution loop in the Node environment

NodeJs event loop

The Event Loop of the browser follows the HTML5 standard, while the Event Loop of the NodeJs complies with the Libuv standard. Therefore, there will be some differences in the execution of the Event. As we all know, NodeJs is actually a RUNTIME of JS, that is, the runtime environment. So the nodeJS API in this environment is mostly executed through callbacks, event publish-subscribe, so what is the order of execution of our code in this environment, how are our different callbacks classified and in what order are they executed, It’s actually determined by our libuv.

┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐ ┌ ─ > │ timers │ │ └ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┬ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┘ │ ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┴ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐ │ │ pending Callbacks │ │ └ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┬ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┘ │ ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┴ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐ │ │ idle, Prepare │ │ └ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┬ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┘ ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐ │ ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┴ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐ │ incoming: │ │ │ poll │ < ─ ─ ─ ─ ─ ┤ connections, │ │ └ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┬ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┘ │ data, Etc. │ │ ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┴ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐ └ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┘ │ │ check │ │ └ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┬ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┘ │ ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┴ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐ └ ─ ─ ┤ close callbacks │ └ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┘Copy the code

Let’s start with what are these six missions for

  • Timers: This phase executes the callbacks set by setTimeout() and setInterval().
  • Pending Callbacks: A small number of I/O callbacks from a previous cycle are deferred until this stage of the cycle.
  • Idle, prepare: Used internally only.
  • Poll: Perform I/O callback, which under appropriate conditions will block at this stage
  • Check: Executes the callbacks set by setImmediate().
  • Close callbacks: execute such as socket.on(‘close’,…) The callback.

If we look at a NodeJS execution diagram found on the Internet, we can see that there are six steps in the diagram. When the code is executed, if we encounter the callback function of these six steps, we put it into the corresponding queue. Then when we finish the synchronization character execution, we switch to the next phase, that is, the timer phase. Stage and the timer will take during the execution of all the callback function is performed at this stage and then into the next phase, it is important to note when we switch in each phase will perform a first all the tasks in the task queue, and then entered the stage of the next task, so we can come to the conclusion that nodejs ring sequence of events

  1. Synchronize code execution, clear microtask queue, execute timer phase callback function (i.e. SetTimeout, setInterval)
  2. When all execution is complete, clear the microtask queue and execute the callback function of the pending Callbacks stage
  3. After all operations are complete, clear the microtask queue and execute the callback function in idle and prepare phases
  4. After all execution is complete, the micro task queue is emptied and the callback function of the poll stage is executed
  5. All done, clear the microtask queue, and perform the check phase’s callback (setImmediate)
  6. When all is done, clear the microtask queue and execute the callback function of the close Callbacks stage
  7. Then cycle stages 1-6

Let’s practice our hands

// Let's look at our execution phaselet fs = require('fs'); / / meetsetTimeout is put into the timer callbacksetTimeout(function(){
        Promise.resolve().then(()=>{
            console.log('then1'); })}, 0); Promise.resolve().then()=>{console.log()'then2'); }); // I/O operations are placed in pending callbacks fs.readfile ('./text.md'.function(){// place the check phasesetImmediate(()=>{
            console.log('setImmediate')}); // Put the microtask queue process.nexttick (function(){
            console.log('nextTick')})});Copy the code

Then we switch to the timer phase, execute the timer callback, print then1, execute the I/O callback, then clear the microtask queue, print nextTick, and then enter the check phase. Clear the Check phase callback output setImmediate

All the rules look at the clouds in the fog, but as long as we summed up the rules, understand their operation mechanism so we will master these rules, good cough, today and learn so much, don’t say don’t say, hurriedly roll to write business code………….