Node's "event loop" is primarily designed to handle high output volumes. This is amazing, which is why node can handle a lot of background operations at the same time in single-threaded situations. This article will focus on how the event loop works, so you can use this magical thing to accomplish your own work.
Event-driven programming (Event-driven programming)
The first thing you need to understand about event loop is the event driven programming (events-driven programming). This was already known in the 1960 's. Today, Event-driven proggramming is widely used in UI processing. JavaScript is primarily used in processing the DOM.
The definition is very simple: Event-driven programming is the control flow of the program is determined by the change of the event or state. The main implementation mechanism is to use a central console to listen for events and invoke the corresponding callback function when the event occurs (the same is true for state changes). Are you familiar? This is the processing mechanism of node's event loop.
JavaScript development in browsers often encounters the. on* () method, such as Element.onclick (), which is used to connect user operations and the DOM. This pattern works very well when a single element can emit a variety of possible events. Node uses this pattern in Eventemitter, which is used primarily in modules such as Server,socket and ' http '. This is useful when an instance needs to emit multiple types of events and states.
Another commonly used pattern is success and failure. There are two ways to implement the mainstream. The first is the callback with the error (Original: "Error Back"), which invokes the callback function as the first parameter when an error occurs. Another method is defined in ES6, using promises.
' Error back ' is used extensively in the ' FS ' module. Technically, some calls emit other events. For example, Fs.readfile (). But only when a success or failure to remind users. The API is designed primarily for system policy, not technical limitations.
Two big misconceptions are that the event mechanism itself is asynchronous. However, this is not right. The following code shows this:
varEventemitter = require (' Events '). Eventemitter;varUtil = require (' util '));functionMyemitter () {Eventemitter.call ( This);} Util.inherits (Myemitter, Eventemitter); MyEmitter.prototype.doStuff=function() {Console.log (' Before '); This. Emit (' Fire '); Console.log (' After ');}varme =NewMyemitter (); Me.on (' Fire ',function() {Console.log (' Emit fired ');}); Me.dostuff ();//Output://before//emit fired// After
Eventemitter appears to be asynchronous because he is always used to signal the completion of an asynchronous operation. However, the Eventemitter API is fully synchronized. The emit method may be called asynchronously, but the listening methods that need to be mostly to the full are executed synchronously in the order in which they were added.
General overview
Node itself relies on a lot of libraries. One of them is libuv. This library is used to handle queues and asynchronous events. Node uses the functionality already available at the core of the operating system at great limits. Request write operations, maintain connections, and more functions that are handled by the system. For example, the connection request is queued by the system until it is processed by node.
You may have known that node has a thread pool and would like to know, "What thread pool do you need if node pushes these responsibilities off?" "This is because the system core does not support doing anything asynchronously. For example, sometimes node needs to lock a thread so that the event loop can be executed without deadlock.
Here's a simplified diagram to explain how the event loop works.
Some of the internal execution mechanisms of the event loop are difficult to give in the diagram:
- All callbacks specified using Process.nextick () are executed at the end of a phase of the event loop (for example, a timer) before entering the next phase. There is a potential risk that the entire event loop will be dragged to death if the Process.nexttrick () method has recursive invocation.
- The pending queue (pending callbacks) is a callback queue (such as a callback passed to Fs.write () that is not processed by another stage (phase).
Event emitter and Event Loop
In order to simplify and interoperate with the event loop, Eventemitter is available. With Eventemitter, it is easy to create an event-based API. Below we will explain some of the main content.
The following code shows a scenario in which a user misses an event because the event is not synchronously emitted:
varEventemitter = require (' Events '). Eventemitter;varUtil = require (' util '));functionmything () {Eventemitter.call ( This); Dofirstthing (); This. Emit (' thing1 ');} Util.inherites (mything, eventemitter);varMT =Newmything (); Mt.on (' Thing1 ',function(){ //never going to happen.});
The problem with the above code is that ' Thing1 ' will never be captured by the user, because mything () must be able to listen for events after initialization is complete. Here is a simple solution that does not require any additional closures:
varEventemitter = require (' Events '). Eventemitter;varUtil = require (' util '));functionmything () {Eventemitter.call ( This); //dofirstthing (); //this.emit (' thing1 ');Setimmediate (EmitThing1, This);} Util.inherits (mything, eventemitter);functionemitThing1 (self) {self.emit (' Thing1 ');}varMT =Newmything (); Mt.on (' Thing1 ',function(){ //BravoConsole.log (' Bravo, thing1 captured. '));});//Bravo, Thing1 captured.
The following code page can run, but consumes more.
functionmything () {Eventemitter.call ( This); //dofirstthing (); //this.emit (' thing1 '); //setimmediate (emitThing1, this);Setimmediate ( This. Emit.bind ( This, ' Thing1 '));}
Another scenario is to trigger an error. It's a hassle to find out what's wrong with your app, and it's simply impossible to troubleshoot without a call stack. An error may cause the call stack to be lost when initialized in the depths of an asynchronous execution. Two of the best ways to solve this problem are to synchronize the emit event, or to make sure that the error has enough relevant information. Take a look at the demo of the following code:
MyThing.prototype.foo =function () { varER =dofirstthing (); if(er) {//emit error asynchronouslySetimmediate (Emiterror, This,NewError (' Bad stuff ')); return; } //emit error synchronously varER =dosecondthing (); if(er) { This. Emit (' Error ', ' more bad stuff '); return; }};
Emit errors should be handled immediately in case the program continues to execute. And it's not a good idea to emit errors in the constructor.
At last
This article only covers a small part of the event loop knowledge. These will be replenished in later articles. However, this is the necessary foundation before continuing. The following article will tell you how event loops interact with the core of the system.
Welcome Dabigatran to learn from each other and make progress together. QQ Group: 58099570 | To be kind, reprint please indicate the source!
Copyright NOTICE: This article for Bo Master original article, without Bo Master permission not reproduced.
Understanding Nodejs's Event Loop