Event loop
Last updated
Last updated
"Event Loop is a programming construct that waits for and dispatches events or messages in a program."
The responsibility of the event loop is to constantly wait for events to occur, and then execute all the handlers for this event in the order of their subscription to this event. When all the handlers for this event have been executed, the event loop will start to continue waiting for the next event trigger, and so on.
When multiple requests are processed concurrently, the above concept is also correct, and can be understood as follows: in a single thread, event handlers are executed one by one in order.
That is, if an event is bound to two handlers, the second handler will start executing only after the first handler has finished executing. The event loop will not check whether there is a new event trigger until all the handlers for this event have been executed. In a single thread, everything is executed in order one by one!
Node uses V8 as the JavaScript execution engine and uses libuv to implement event-driven asynchronous I/O. Its event loop uses the default event loop of libuv. In src/node.cc,
This code creates a node execution environment. You can see the third line of uv_default_loop() in it. This is a function in the libuv library, which initializes the uv library itself and the default_loop_struct in it, and returns a pointer to it, default_loop_ptr. After that, Node will load the execution environment and complete some setup operations, and then start the event loop:
more is used to indicate whether to perform the next loop. env->event_loop() will return the default_loop_ptr saved in env before, and the uv_run function will start the libuv event loop in the specified UV_RUN_ONCE mode. In this mode, uv_run will process at least one event: this means that if there is no I/O event that needs to be processed in the current event queue, uv_run will block until there is an I/O event that needs to be processed or the next timer time is up. If there are no I/O events or timer events at the moment, uv_run returns false.
Next, Node will decide the next step based on the situation of more:
If more is true, continue to run the next loop.
If more is false, it means that there are no events waiting to be processed. EmitBeforeExit(env); triggers the 'beforeExit' event of the process, checks and processes the corresponding processing functions, and then directly exits the loop.
Finally, trigger the 'exit' event, execute the corresponding callback function, and Node ends, and some resource release operations will be performed later.
In libuv, the event loop updates its time at the beginning of each loop to achieve timing function, and I/O events are divided into two categories:
Network I/O uses the non-blocking I/O solution provided by the system, such as epoll on Linux and IOCP on Windows.
File operations and DNS operations do not have (good) system solutions, so libuv builds its own thread pool to perform blocking I/O.
In addition, we can also throw custom functions into the thread pool to run. After the operation is completed, the main thread will execute the corresponding callback function. However, Node has not added this function to JavaScript, which means that it is impossible to start a new thread for parallel execution in JavaScript with native Node.
In the entry point src/node.js
, the processNextTick
method constructs the process.nextTick
API.
process._tickCallback
is hung on the process
object as the callback function of nextTick, and is called back by the C++ layer.
Register _tickCallback
to env
's tick_callback_function
through process._setupNextTick
.
In the src/async_wrap.cc
file, we find the following call:
Otherwise, _tickCallback
is called through tick_callback_function
.
At this point, I also have a question: what if there is no asynchronous IO? How is it driven?
We come to lib/module.js
, as follows:
After Module._load
loads the main script, it calls _tickCallback
to handle the first tick.
So the above question has an answer. nextTick
is mainly driven by uv__io_poll
. Why do we say mainly? Because it may also be driven by the Timer module. The specific details are left for readers to study.
http://acemood.github.io/2016/02/01/event-loop-in-javascript/
With this question in mind, let's take a look at how the JS layer's nextTick is driven.