Home  >  Article  >  Web Front-end  >  A brief discussion on timers in Node.js

A brief discussion on timers in Node.js

高洛峰
高洛峰Original
2017-02-08 16:18:261007browse

This article shares with you the relevant information about timers in Node.js. It is very comprehensive and detailed. Friends who need it can refer to it.

Implementation of timer in Node.js

As mentioned in the previous blog post, timer in Node is not implemented by opening a new thread, but directly Done in the event loop. The following uses several JavaScript timer examples and Node related source code to analyze how the timer function is implemented in Node.

Characteristics of the timer function in JavaScript

Whether it is Node or the browser, there are two timer functions, setTimeout and setInterval, and their working characteristics are basically The same, so only Node is used as an example for analysis below.

We know that the timer in JavaScript is not different from the underlying scheduled interrupt of the computer. When an interrupt arrives, the currently executing code will be interrupted and transferred to the scheduled interrupt processing function. When the JavaScript timer expires, if there is no code being executed in the current execution thread, the corresponding callback function will be executed; if there is code currently being executed, the JavaScript engine will neither interrupt the current code to execute the callback, nor start The new thread executes the callback, but it is processed after the current code is executed.

console.time('A')
setTimeout(function () {
  console.timeEnd('A');
}, 100);
var i = 0;
for (; i < 100000; i++) { }

Execute the above code, you can see that the final output time is not about 100ms, but a few seconds. This shows that the scheduled callback function is indeed not executed before the loop is completed, but is postponed until the end of the loop. In fact, during JavaScript code execution, all events cannot be processed, and new events must be processed until the current code is completed. This is why the browser becomes unresponsive when running time-consuming JavaScript code in it. In order to deal with this situation, we can use the Yielding Processes technique to divide the time-consuming code into small chunks (chunks). After each chunk is processed, setTimeout is executed once, and it is agreed that the next chunk will be processed after a short period of time. During this period During idle time, the browser/Node can process queued events.

Supplementary information

There is a more detailed discussion of advanced timers and Yielding Processes in Chapter 22 Advanced Techniques of JavaScript Advanced Programming, Third Edition.

Timer implementation in Node

libuv's initialization of uv_loop_t type

The previous blog post mentioned that Node will call libuv's uv_run function to start default_loop_ptr For event scheduling, default_loop_ptr points to a variable default_loop_struct of type uv_loop_t. When Node starts, it will call uv_loop_init(&default_loop_struct) to initialize it. The excerpt of uv_loop_init function is as follows:

int uv_loop_init(uv_loop_t* loop) {
 ...
 loop->time = 0;
 uv_update_time(loop);
 ...
}

You can see that the time field of loop is first assigned a value of 0 , and then call the uv_update_time function, which will assign the latest counting time to loop.time.

After the initialization is completed, default_loop_struct.time has an initial value, and time-related operations will be compared with this value to determine whether to call the corresponding callback function.

libuv's event scheduling core

As mentioned earlier, the uv_run function is the core part of the libuv library's event loop implementation. The following is its flow chart:

A brief discussion on timers in Node.js

Here is a brief description of the above logic related to the timer:

Update the time field of the current loop, this field marks the "now" under the current loop concept;

Check whether the loop is alive, that is to say, check whether there are any tasks (handlers/requests) that need to be processed in the loop. If not, there is no need to loop;
Check the registered timer, if a certain timer The time specified in is behind the current time, indicating that the timer has expired, so its corresponding callback function is executed;
Perform I/O polling (that is, blocking the thread and waiting for the I/O event to occur). If the following If no I/O is completed when a timer expires, it stops waiting and executes the callback of the next timer.

If an I/O event occurs, the corresponding callback will be executed; since another timer may have expired during the callback execution time, the timer must be checked again and the callback executed.
(Actually (4.) here is more complicated, not just a one-step operation. This description is just to not involve other details and focus on the implementation of timer.)
Node will keep calling uv_run until the loop is no longer alive.

Timer_wrap and timers in Node

There is a TimerWrap class in Node, which is registered as the timer_wrap module inside Node.

NODE_MODULE_CONTEXT_AWARE_BUILTIN(timer_wrap, node::TimerWrap::Initialize)
The TimerWrap class is basically a direct encapsulation of uv_timer_t, and NODE_MODULE_CONTEXT_AWARE_BUILTIN is a macro used by Node to register built-in modules.

After this step, JavaScript can get this module to operate. The src/lib/timers.js file uses JavaScript to encapsulate the timer_wrap function and exports exports.setTimeout, exports.setInterval, exports.setImmediate and other functions.

Node startup and global initialization

The previous article mentioned that Node will load the execution environment LoadEnvironment(env) when it starts. A very important step in this function is to load src/node.js and execute it. src/node.js will load the specified module. And initialize global and process. Of course, functions such as setTimeout will also be bound to the global object by src/node.js.

The above is the entire content of this article, I hope you all like it.

For more articles related to timers in Node.js, please pay attention to the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn