Node.js event, events module and EventEmitter class

event loop

Node.js is a single process and single thread application. However, because of the asynchronous execution callback interfaces provided by the V8 engine, a large number of concurrency can be handled through these interfaces, so the performance is very high.

Almost every API of Node.js supports callback functions.

Basically, all event mechanisms in Node.js are implemented in the observer pattern in the design pattern.

Node.js single thread is similar to entering a while(true) event loop until no event observer exits. Each asynchronous event generates an event observer. If an event occurs, the callback function is called

Event driver

Node.js uses the event driven model. When the web server receives a request, it closes it, processes it, and then serves the next web request.

When the request is completed, it is put back into the processing queue. When it reaches the beginning of the queue, the result is returned to the user.

This model is very efficient and scalable, because the web server always accepts requests without waiting for any read and write operations. (this is also called non blocking IO or event driven IO)

In the event driven model, a main loop will be generated to listen for events and trigger the callback function when an event is detected.

The whole event driven process is implemented in this way, which is very concise. It is somewhat similar to the observer mode. An event is equivalent to a subject, and all handler functions registered to the event are equivalent to observers.

Event processing method based on built-in events module

Node.js has multiple built-in events. We can bind and listen to events by introducing the events module and instantiating the EventEmitter class, as shown in the following examples:

# Introducing the events module
var events = require('events');

# Create an event trigger object eventsexmitter
var eventEmitter = new events.EventEmitter();

# Binding events and event handlers
eventsEmitter.on('eventName',eventHandler);

# Event triggered by program
eventEmitter.emit('eventName');

Example

# main.js
// Introducing the events module
var events = require('events');
// Create eventEmitter object
var eventEmitter = new events.EventEmitter();
 
// Create event handler
var connectHandler = function connected() {
   console.log('Connection succeeded.');
  
   // Trigger data_received event 
   eventEmitter.emit('data_received');
}
 
// Binding connection event handler
eventEmitter.on('connection', connectHandler);
 
// Bind data using anonymous functions_ Received event
eventEmitter.on('data_received', function(){
   console.log('Data received successfully.');
});
 
// Trigger connection event 
eventEmitter.emit('connection');
 
console.log("Program execution completed.");

Node.js EventEmitter class

Nodejs sends an event to the event queue when all asynchronous I/O operations are completed

Many objects of Nodejs distribute events, such as:

A net.Server object will trigger an event every time there is a new connection

An fs.readStream object will trigger an event when the file is opened

All of these event generating objects are instances of events.EventEmitter

// Introducing the events module
var events = require('events');
// Create eventEmitter object
// The events module only provides the EventEmitter object. The core is the encapsulation of event trigger and event listener functions
var eventEmitter = new events.EventEmitter();

If an error occurs during instantiation of the EventEmitter object, the error event will be triggered. The newListener event is triggered when a new listener is added, and the removeListener event is triggered when the listener is removed.

# events module documentation

# Other methods
# Event represents the event name in string format
# listener represents a callback function

// Adds a listener to the end of the listener array
.addListener(event, listener)

// Registers listeners for the specified event
.on(event, listener)

// A single listener. Release the listener after departure
.once(event,listener)

// Remove listener
.removeListener(event, listener)

// Remove all listeners
.removeAllListeners([event])

// Set the maximum number of listeners (the default is 10, which will be warned if exceeded)
.setMaxListeners(n)

// Returns the list of specified listeners
.listeners(event)

// Execute each listener in listener order
.emit(event, [arg1], [arg2], [...])


# Class method (static method)
                              
// Returns the number of event listeners
events.emitter.listenerCount(eventName)


# Event (module's own)

// This event is triggered when a new listener is added
newListener

// Removes a listener from the specified listener array. It should be noted that this operation will change the indexes of those listeners after the deleted listeners
removeListener


# error event
EventEmitter Defines a special event error,It contains the semantics of error, which is usually triggered when we encounter an exception error event.
When error When triggered, EventEmitter Specifies that if there is no responding listener, Node.js It will treat it as an exception, exit the program and output an error message.
We usually want to trigger error Event object to set the listener to avoid the crash of the whole program after encountering an error.

# This code will crash because no listener is set for error
var events = require('events'); 
var emitter = new events.EventEmitter(); 
emitter.emit('error'); 
// The program crashes and displays the following message:
// ···
// throw e; // process.nextTick error, or 'error' event on first tick 
// ···

Inherit EventEmitter

Most of the time, we don't use EventEmitter directly, but inherit it in the object.

All core modules supporting event response, including fs, net and http, are subclasses of EventEmitter.

Why? There are two reasons:

First of all, the event implemented by an object with an entity function conforms to semantics, and the monitoring and occurrence of events should be the method of an object.

Secondly, the object mechanism of JavaScript is prototype based and supports partial multiple inheritance. Inheriting EventEmitter will not disturb the original inheritance relationship of the object.

Posted on Thu, 28 Oct 2021 01:54:37 -0400 by intergroove