Talking about the timer in Node. js and talking about the timer in Node. js
Implementation of timer in Node. js
As mentioned in the previous post, timer in Node is not implemented through a new thread, but directly completed in event loop. The following uses several JavaScript timer examples and Node-related source code to analyze how timer is implemented in Node.
Features of the timer function in JavaScript
Both the Node and the browser have the setTimeout and setInterval timer functions, and their features are basically the same. Therefore, the following uses Node as an example for analysis.
We know that the timer in JavaScript is not the same as the Scheduled interrupt at the bottom of the computer. When the interruption arrives, the current Execution Code is interrupted and switched to the scheduled interrupt processing function. When the JavaScript timer arrives, If no code is being executed by the current execution thread, the corresponding callback function will be executed. If the code is being executed, the JavaScript engine does not interrupt the current code to execute the callback, nor start a new thread to execute the callback. Instead, it processes the code after the current code is executed.
console.time('A')setTimeout(function () { console.timeEnd('A');}, 100);var i = 0;for (; i < 100000; i++) { }
Run the above Code and you can see that the final output time is not about ms, but several seconds. This indicates that the scheduled callback function is not executed before the loop is completed, but is postponed to the end of the loop. In fact, in JavaScript code execution, all events cannot be processed. You must wait until all the current code is complete before you can handle new events. This is why the browser loses response when it is running time-consuming JavaScript code in the browser. To cope with this situation, we can adopt the Yielding Processes technique to divide the time-consuming code into chunks, and execute setTimeout once after each piece is processed, it is agreed that the next part will be processed after a short period of time, while during this idle period, the browser/Node can process events in the queue.
Additional information
The advanced timer and Yielding Processes are discussed in detail in chapter 22nd of the third edition of JavaScript advanced programming.
Timer implementation in Node
Libuv initializes uv_loop_t
As mentioned in the previous blog, Node will call the uv_run function of libuv to start default_loop_ptr for event scheduling. default_loop_ptr points to a variable of the uv_loop_t type, default_loop_struct. When Node starts, it will call uv_loop_init (& default_loop_struct) to initialize it. The uv_loop_init function excerpt is as follows:
int uv_loop_init(uv_loop_t* loop) { ... loop->time = 0; uv_update_time(loop); ...}
We can see that the time field of the loop is assigned 0 first, and then the uv_update_time function is called. This will assign the latest count time to the loop. time.
After initialization, default_loop_struct.time has an initial value. operations related to time will be compared with this value to determine whether to call the corresponding callback function.
Libuv event scheduling Core
As mentioned above, the uv_run function is the core part of implementing event loop in the libuv library. The following is the flowchart:
The above timer-related logic is briefly described here:
Update the time field of the current loop. This field indicates the current field in the current loop concept ";
Check whether the loop is alive. That is to say, check whether there are handlers/requests tasks in the loop. If not, you do not need to loop;
Check the registered timer. If the specified time in a timer lags behind the current time, it indicates that the timer has arrived, and the corresponding callback function is executed;
Execute I/O polling once (that is, to block the thread and wait for the I/O event to happen). If no I/O is completed when the next timer expires, stop waiting, execute the callback of the next timer.
If an I/O event occurs, the corresponding callback is executed. Because timer may expire again during the execution of the callback, check the timer again and execute the callback.
(Actually (4.) This is complicated, not just a one-step operation. It is described only to focus on the implementation of timer without involving other details .)
Node will always call uv_run until the loop is no longer alive.
Timer_wrap and timers in Node
The Node has a TimerWrap class and is registered as the timer_wrap module in the Node.
NODE_MODULE_CONTEXT_AWARE_BUILTIN (timer_wrap, node: TimerWrap: Initialize)
The TimerWrap class is basically a direct encapsulation of uv_timer_t. NODE_MODULE_CONTEXT_AWARE_BUILTIN is the macro used by Node to register the built-in module.
After this step, JavaScript can obtain this module for operation. The src/lib/timers. js file encapsulates the timer_wrap function in JavaScript format and exports functions such as exports. setTimeout, exports. setInterval, and exports. setImmediate.
Node startup and global initialization
The previous article mentioned that the Node will load the execution environment LoadEnvironment (env) at startup. A very important step in this function is to load src/node. js and execute, src/node. js loads the specified module and initializes global and process. Of course, functions such as setTimeout will also be bound to the global object by src/node. js.
The above is all the content of this article. I hope you will like it.