Node event loop

We know, Node is based on the Chrome V8 engine, which means that it also has an event loop js engine is Event Loop mechanism. But the Node is running on the server side, there is different from the browser side. For example, more setImmediate, process.nextTick and other than asynchronous API browser. Then the event loop mechanism certainly is not the same. Here we look at how Node event loop is a kind of operation.

Node event loop

1. Node event loop can simply be seen as by a thread (ie js main thread) with several queues (such as nextTickQueue, microTaskQueue, etc.) thereof. The main thread acquired constantly from the queue and execute tasks, similar while (true) {} which constantly circulates

2. In the main event loop is completed above thread

3. The event loop including synchronous asynchronous tasks with the task synchronization task execution priority is greater than the asynchronous task, that is task synchronization is always performed before asynchronous tasks:

. 1 the console.log ( 'I'm a synchronization task, a first output' )
 2 process.nextTick (() => {
 . 3     the console.log ( 'I asynchronous tasks, the third output' ) 
 . 4  })
 . 5 the setTimeout ( () => {
 . 6      the console.log ( 'I asynchronous tasks, the fourth output' )
 . 7  })
 . 8 setImmediate (() => {
 . 9      the console.log ( 'I asynchronous tasks, the fifth output' )
 10  })
 . 11 the console.log ( 'I'm a synchronization task, a second output' )
 12  // output 
13  // I synchronization task, a first output 
14  // I synchronization task, a second output 
15  //My task is asynchronous, and the third output 
16  // I am asynchronous tasks, the fourth output 
17  // I am asynchronous tasks, the fifth output
View Code

4. In order to facilitate understanding, here for the time being put into asynchronous tasks we often say that the micro-task (microTask) with macro task (macroTask) . microTask contains nextTickQueue with microTaskQueue ( for ease of understanding, the latter microTask refer nextTickQueue with microTaskQueue ) , macroTask contains the setTimeout / setInterval / setImmediate / IO callback / callback HTTP and so on. Which microTask will be executed in the current cycle, and macroTask is only performed after completion of the current cycle synchronization tasks performed inside with microTask inside the task. And in the implementation of macroTask, priority will perform synchronization tasks inside, then check microTask there are no tasks to perform any complete before continuing to the next cycle, if not directly execute the next macro task. Such a round infinite loop know the service exit. This is the event loop.

5. In the current cycle, the order of execution js thread is this: synchronization tasks> nextTickQueue> microTaskQueue , that is, to perform synchronization tasks, task synchronization after executing the check nextTickQueue there is no task queue, any execution nextTickQueue, until after nextTickQueue inside the task executed, then there is no judgment microTaskQueue task queue, any execution, if not continue to the next cycle. Note that when performing microTaskQueue task, if they appear process.next () with Promise.then (), will hold off until execution microTaskQueue, until microTaskQueue is empty, then judge nextTickQueue:

 1 console.log('1')
 2 process.nextTick(() => {
 3     console.log('tick 1')
 4     process.nextTick(() => {
 5         console.log('tick 2')
 6     })
 7 })
 8 
 9 Promise.resolve().then(() => {
10     console.log('Promise.then 1')
11     process.nextTick(() => {
12         console.log('tick 3')
13     })
14     Promise.resolve().then(() => {
15         console.log('Promise.then 2')
16     })
17 })
18 // 输出结果:
19 // 1
20 // tick 1
21 // tick 2
22 // Promise.then 1
23 // Promise.then 2
24 // tick 3
View Code

6. When finished after the execution of the current macro task, which will go to the queue to determine whether you have a macro task, any out continues.

7. The event loop architecture

 

 

 8. We can see from the figure, the event loop is divided into six stages, which are executed according to the order of FIG. Each stage has its own queue, the storage of the corresponding task, each execution stage will traverse the stage inside the task, in accordance with the FIFO principle is being applied only when a stage will be implemented after the completion of the implementation of a task stage. It should be noted that nextTickQueue with microTaskQueue is performed at the time of the metropolitan area each stage of each task performed. This means that if Timer queue there are three tasks, each performing a task will be to determine whether there are tasks nextTickQueue with microTaskQueue, any first execution, and then perform the next task after the execution. If the two endless queues have been executed, it will lead to follow-up the task of blocking, the last system crash. So I understand as microTask is attached to macroTask, each macroTask may contain their own microTask, only when the current macroTask subsidiary of executing the microTask will be performed next macroTask.

9. Following is a brief say at what stage are each separately:

  1) Timer phases: phase timer, mainly deal with setTimeout / setInterval callback function. When entering this stage, the main thread will determine whether the current time to meet the requirements of a timer, that is, whether the delay timer is set to, then it is executed, otherwise proceed to the next stage.

  2) Pending I / O callbacks stages:. Callback phase IO, IO processing callback function.

  3) Idle, prepare Phase:. Node internal operation, particularly not clear

  4) Poll stages: Polling, IO wait for the event has not yet returned

  5) Check phase: the implementation of setImmediate callback.

  6) Close callbacks:. Callback performed off request, such socket.on ( 'close', () => {})

This is probably explained by the six stages, we can know that when setTimeout delay is zero (ideal state), when, in fact, is a priority in the implementation of setImmediate, but in practice, this is not guaranteed, setTimeout because there may be a slight delay, leading to the callback function has not yet into the queue Timer stage, so setImmediate will give priority to the implementation of setTimeout. It depends on the performance of the machine with some other uncontrollable factors. But the following code is able to ensure setImmediate precedence over setTimeout, and why? Because setImmediate is in the fifth stage, and IO callback is the second stage, setTimeout is the first stage. When executed IO callbacks, the first phase (setTimeout) have finished the race, according to the order of the fifth stage (setImmediate) will run first.

 1 fs.readFile('./test1.js', 'utf-8', () => {
 2     setTimeout(() => {
 3         console.log('setTimeout in IO callback')
 4     })
 5     setImmediate(() => {
 6         console.log('setImmediate in IO callback')
 7         process.nextTick(() => {
 8             console.log('process in IO-setImmediate callback')
 9         })
10     })
11     process.nextTick(() => {
12         console.log('process in IO callback')
13     })
14     console.log('sync in IO callback')
15 })
16 // 输出结果:
17 // sync in IO callback
18 // process in IO callback
19 // setImmediate in IO callback
20 // process in IO-setImmediate callback
21 // setTimeout in IO callback
View Code

 setImmediate comparison with setTimeout: setTimeout calculates the current task is executable, it can perform. And setImmediate no need to calculate, but directly placed in the queue, so the relative performance setImmediate will be better setTimeout

Guess you like

Origin www.cnblogs.com/l-c-blog/p/11746410.html