A detailed explanation of the event mechanism in Node.js _node.js

Source: Internet
Author: User
Tags emit event listener readfile

Objective

In front-end programming, events are widely used, with various events on the DOM. After the large-scale application of Ajax, asynchronous requests are more widely recognized, and Ajax is also based on the event mechanism.

Usually JS gives us the first impression of running the script on the client browser, through Node.js we can run JavaScript on the server side.

Node.js is a single-threaded non-blocking asynchronous I/O, asynchronous I/O refers to when the I/O operation is encountered, the thread does not block but do the following operations, then the I/O operation is completed, how does the thread know the operation completed?

When the operation completes the time-consuming I/O operation, the thread of the I/O operation is notified as an event, the thread will handle the event at a specific time, and the next step, in order to complete the asynchronous I/O, the thread must have the mechanism of the event loop, insisting on whether there are any unfinished Complete the processing of these events sequentially.

For blocking I/O, the thread encounters time-consuming I/O operations that stop continuing and wait for the operation to complete, at which point the thread cannot accept other operational requests and, in order to provide throughput, multiple threads must be created, each thread responding to a client's request, but at the same time A CPU core can only run one thread, and multiple threads must switch between different threads if they want to execute.

As a result, the creation of node.js threads is less than as well as the cost of the thread switching, the cost of the thread switching is very large, you need to allocate memory, included in the schedule, while the thread switch when the need to perform a memory page, and so on, using a single-threaded way to reduce these operations. But this kind of programming method also has the shortcoming, does not conform to the people's design thinking.

Node.js is an event-based pattern to implement asynchronous I/O. When it is started, it will iterate over whether there is a completed event, then execute, and then notify the thread in the form of another event after the execution is completed, and the event will be added to the list of unfinished events. The thread traverses the event and executes it at some point in time, in which a large task needs to be divided into small events, and Node.js is also suitable for dealing with high I/O, low logic scenarios.

The following example shows an asynchronous file read:

var fs = require (' FS '); 
Fs.readfile (' file.txt ', ' utf-8 ', function (err, data) { 
if (err) { 
<span style= ' white-space:pre ' > </ Span>console.error (err); 
} else { 
<span style= "White-space:pre" > </span>console.log (data); 
} 
); 
[JavaScript] View plain copy

Read the fs.readFile file asynchronously, and then the process will continue. Does not wait for it to read the file, when the file is read, will post an event, the execution thread traversal to the event will perform the corresponding operation, here is the implementation of the corresponding callback function, in the example string end than the file content first printed.

Node.js Event API

events.EventEmitter: Eventemitter provides encapsulation of event launch and event listener functions in Node.js, each of which consists of a string identifying the event name and corresponding operation.

Monitoring of events:

var events = require ("events"); 
var emitter = new events. Eventemitter (); 
 <span style= "font-family:arial, Helvetica, Sans-serif;" >emitter.on ("EventName", function () {</span> 
  console.log ("EventName event occurs") 

Publication of events:

 
 

We can pass in more than one argument when the event is published, the first parameter represents the name of the event, and the arguments that follow indicate the parameters passed in, which are passed into the callback function of the event.

EventEmitter.once("eventName", listener) : Registers a listener that executes only once for an event, and the listener is lifted when the event first occurs and the listener is triggered, and the listener is not executed after the event occurs.

EventEmitter.removeListener(event, listener) : Remove listener for Event

EventEmitter.removeAllListeners(event): Remove all listeners from the event

EventEmitter.setMaxListeners(n): Node.js Default Single Event the maximum number of listeners is 10, if more than 10 will give a warning, this is to prevent memory overflow, we can change this limit set to other numbers, if set to 0 means no restrictions.

EventEmitter.listeners(event) : Returns a list of listeners for an event

Collaboration between multiple events
In a slightly larger application, the separation between data and Web servers is inevitable, such as Sina Weibo, Facebook, Twitter, and so on. The advantage is that the data source is unified, and rich client programs can be developed for the same data source.

In the case of Web applications, when rendering a page, it is often necessary to pull data from multiple data sources and eventually render to the client. Node.js in this scenario, it is natural and convenient to simultaneously initiate requests for multiple data sources concurrently.

Api.getuser ("username", function (profile) {
 //Got-profile
});
Api.gettimeline ("username", function (timeline) {
 //Got the Timeline
});
Api.getskin ("username", function (skin) {
 //Got the Skin
});

Node.js through the asynchronous mechanism to make the request without blocking, to achieve the purpose of parallel request, effectively invoke the underlying resources. However, the problem in this scenario is that the coordination of multiple event response results is not gracefully supported by Node.js native.

To achieve the next step in order to reach the results of three requests, the program may be changed to the following:

Api.getuser ("username", function (profile) {
 Api.gettimeline ("username", function (timeline) {
  Api.getskin ("username", function (skin) {
   //TODO
  });
 });

This will cause the request to become serial and not maximize the use of the underlying API server.

To address this type of problem, I have written a module to implement multiple event collaboration, the following is an improved version of the code above:

var proxy = new Eventproxy ();
Proxy.all ("Profile", "timeline", "Skin", function (profile, timeline, skin) {
 //TODO
});
Api.getuser ("username", function (profile) {
 proxy.emit (' profile ', profile);
});
Api.gettimeline ("username", function (timeline) {
 Proxy.emit ("timeline", timeline);
});
Api.getskin ("username", function (skin) {
 proxy.emit ("Skin", skin);
});

Eventproxy is also a simple implementation of the event listener model, which cannot be merged into Node.js because the underlying implementation is different from the eventemitter of Node.js. But it provides more powerful functionality than Eventemitter, and the API stays consistent with the eventemitter, keeps up with node.js ideas and can be applied to the front-end.
The all method here is to execute the callback function after listening to the three methods of profile, timeline, and skin, and to pass in the received data.

Finally, a solution to multiple event collaboration is introduced, compile the idea through the runtime (can also be compiled before running), the synchronous thinking of the code into the final asynchronous code to execute, you can write code by synchronous thinking to write, you can enjoy the convenience of synchronous thinking writing, asynchronous execution of high-performance performance.

If written through Jscex, the following will be the form:

var data = $await (Task.whenall ({
 profile:api.getUser ("username"),
 timeline:api.getTimeline ("username"),
 Skin:api.getSkin ("username")
});
Use Data.profile, Data.timeline, Data.skin
/TODO

Using event queues to solve avalanche problems

The so-called avalanche problem, is in the cache failure scenario, large concurrent high access volume at the same time into the database query, the database can not withstand such a large query request, and then affect the overall site response to slow.

So how do you deal with this situation in Node.js?

var select = function (callback) {
  db.select ("SQL", function (results) {
   callback (results);
  });
 

The above is a database query call, if the site just started, this time there is no data in the cache, and if the traffic is huge, the same SQL will be sent to the database repeatedly query, affecting the overall performance of the service. One improvement is to add a state lock.

var status = "Ready";
var select = function (callback) {
  if (status = = "Ready") {
   status = "Pending";
   Db.select ("SQL", function (results) {
    callback (results);
    Status = "Ready";}
   );
  }
 ;

This scenario, however, calls the select hair multiple times, and only the first call is in effect, and the subsequent select has no data service. So it's time to introduce the event queue:

var proxy = new Eventproxy ();
var status = "Ready";
var select = function (callback) {
  proxy.once ("selected", callback);
  if (Status = = "Ready") {
   status = "Pending";
   Db.select ("SQL", function (results) {
    proxy.emit ("selected", results);
    Status = "Ready";}
   );
  }
 ;

This utilizes the method of the Eventproxy object once , pressing all the requested callbacks into the event queue and using it to remove the monitor once, ensuring that each callback is executed only once. For the same SQL statement, ensure that the same query starts to the end of the time always only once, the incoming call during this query, just wait for the data in the queue to be ready, save the duplicate database call overhead. Because of node.js single-threaded execution, there is no need to worry about state issues here. This approach can also be applied to other remote-invocation scenarios, even if there is no caching policy externally, which can effectively save recurring overhead. You can also use Eventemitter instead of eventproxy here, but there may be too many listeners, a warning, a call to setMaxListeners(0) remove warnings, or a larger warning threshold.

Summarize

The above is about the Node.js in the event mechanism of the whole content, I hope this article for everyone's study or work can bring some help, if there is doubt you can message exchange.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.