Node.js learning 5 (events)

1, Node JS event loop

       Node.js is a single process and single thread application, but because of the asynchronous execution callback interface provided by V8 engine, a large number of concurrency can be handled through these interfaces, so the performance is very high.
       Node.js almost every API supports callback functions.
       Node.js basically all the event mechanisms are implemented with 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

2, 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.
Note: thread is the smallest unit of the whole program, that is, a program is a process, and at least one thread must be run in a process.
On node There are three main types of roles in the event mechanism of JS: event, event emitter and event listener
       Node.js has multiple built-in events. We can bind and listen to events by introducing the events module and instantiating the EventEmitter class. For example:

//Introducing the events module
var events = require('events');
//Create eventEmitter object
var eventEmitter = new events.EventEmitter();
//Binding events and event handlers
eventEmitter.on('eventName',eventHandler);
//Trigger event
eventEmitter.emit('eventName');

3, Event trigger

       Node. Most of the core API s of JS are built around the customary asynchronous event driven architecture, in which some types of objects (called "triggers") trigger named events so that Function objects ("listeners") are called.
EventEmitter class: event emitter, also known as event trigger. All objects that may trigger events are instance objects integrating subclasses of EventEmitter class, which expose EventEmitter The on () function allows one or more functions to be bound to the named event triggered by the object. Typically, the event name is a humped string, but any valid JavaScript property key can also be used.
When the EventEmitter object triggers an event, all functions bound to that particular event are called synchronously. Any value returned by the called listener will be ignored and discarded.
EventEmitter calls all listeners synchronously in the order of registration. This ensures the correct sequencing of events and helps avoid race conditions and logical errors. When appropriate, listener functions can use setImmediate() or process The nexttick () method switches to an asynchronous mode of operation.

1. EventEmitter class

The EventEmitter class is defined and exposed by the events module:

const EventEmitter = require('events');

For all eventemitters, the event 'newListener' is triggered when a new listener is added, and the event 'removeListener' is triggered when an existing listener is deleted.

2. Method of event trigger

On node JS, many methods are defined for the EventEmitter class, and all processing related to the binding and unbinding of the object's event handling function depends on the calls of these methods.
Common methods: (event: for event name, listener: for event handling function)

Method name and parametersdescribe
addListener(event,listener)Event listener function, emitter Alias of on (eventName, listener).
on(event, listener)Bind the event handler function (alias of addListener method) to the specified object
once(event, listener)Specifies an event handler that executes only once on the specified object
removeListener(event, listener)Delete event
setMaxListeners(n)Specifies the maximum number of object handler functions. n is a positive value, representing the maximum number of event handler functions that can be specified
listeners(event)Gets all event handlers for the specified object
emit(event, [arg1], [arg2], [...])Manually trigger the specified event
newListener(event,Listener)Add a new listener

(1) on method of EventEmitter class

emitter.on(eventName, listener);

EventName < string > | < symbol > the name of the event.
Listener < function > callback function
Return: < EventEmitter >
Add the listener function to the end of the listener array for the event named eventName. Do not check whether a listener has been added. Multiple calls that pass in the same eventName and listener combination will result in multiple additions and calls to listener. By default, event listeners are called in the order they are added.

Example 1: when the server receives the client request, it outputs the target address (URL address) of the client request in the console window, and ends the response immediately using the end method of the response object.

const http = require('http');
//Create server object
let server = http.createServer();
//Bind event request to server object
server.on('request',function (req,res){
    //Output the address of the request object
    console.log('Request address:',req.url);
    //The server closes the connection with the client and sends a response message
    res.end('hello world');
})
//Server start listening
server.listen(8089,'127.0.0.1');



Example 2: you can also bind multiple event handling functions to the same event through the execution of multiple on methods.

var http = require("http");
//Create server object
var server = http.createServer();
//Bind multiple event handlers to the server object
server.on('request',function(req,res){
    console.log('Client request received')
})
server.on("request",function(req,res){
    console.log('Processing client requests')
    console.log(req.url);
    res.end('hello');
})
server.on('request',function(req,res){
    console.log('Send response completed')
})
//Server start listening
server.listen(1337,"127.0.0.1");


(2) once method of EventEmitter class

emitter.once(eventName, listener);

EventName < string > | < symbol > the name of the event.
Listener < function > callback function
Return: < EventEmitter >
Add a single listener function for the event named eventName. The next time eventName is triggered, this listener will be removed and called again.
The once method is similar to the on method. It is used to bind the event handling function to the specified event. The difference is that the event handling function is terminated immediately after it is executed once, that is, the event handling function will be executed only once. The parameters used by the once method are the same as those used by the on method.
By default, event listeners are called in the order they are added.

var http = require("http");
//Create server object
var server = http.createServer();
//Bind multiple event handlers to the server object
server.once('request',function(req,res){
    console.log('Client request received')
})
server.on("request",function(req,res){
    console.log('Processing client requests')
    console.log(req.url);
    res.end();
})
server.once('request',function(req,res){
    console.log('Send response completed')
})
//Server start listening

server.listen(80,function(){
    console.log('http://127.0.0.1')
});

It can be seen from the results that the event handler bound to the once method is executed only once.

(3) Use the removeListener method to cancel the event handler

emitter.removeListener(eventName, listener);

eventName < string > | < symbol >
listener < Function >
Return: < EventEmitter >
Removes the specified listener from the listener array for the event named eventName.
removeListener() deletes at most one listener instance from the listener array. If any single listener has been added to the listener array of the specified eventName more than once, removeListener() must be called more than once to delete each instance.
Once an event is triggered, all listeners bound to it when triggered are called in turn. This means that any removeListener() or removeAllListeners() calls after triggering and before the last listener completes execution will not remove them from the ongoing emit(). Subsequent events run as expected.
Examples are as follows:

const event = require('events');
//Create an instance object of EventEmitter
const myEmitter = new event.EventEmitter();
const f1 = function (){
    console.log('f1 The result is 1');
    myEmitter.removeListener('conduct',f2)
};
const f2 = function (){
    console.log('f2 The result is 2')
};
myEmitter.on('conduct',f1);
myEmitter.on('conduct',f2);
//Manually triggered event
myEmitter.emit('conduct');
//The result is 1 and 2. It can be seen that although we delete f2 in f1, it is still called
myEmitter.emit('conduct');
//The result is 1 and f2 is deleted

When a single function is added multiple times as a handle to a single event (as shown in the following example), removeListener() will delete the recently added instance. For example:

const event = require('events');
const myEmitter = new event.EventEmitter();
function f1(){
    console.log('Alone, hanging like a shadow');
}
function f2(){
    console.log('The north wind rolls the ground, the grass breaks, and the snow flies in August')
}
myEmitter.on('bear6',f1);
myEmitter.on('bear6',f2);
myEmitter.on('bear6',f1);
myEmitter.on('bear6',f2);
myEmitter.removeListener('bear6',f2);
myEmitter.emit('bear6');
//We bind multiple events with the same name to myEmitter, and removeListener() deletes the recently added instance.

(4) Customize events and trigger them

emitter.emit(eventName[, ...args]);

eventName < string > | < symbol >
... args < any > custom parameters
Return: < Boolean >
Call each listener registered for the event named eventName synchronously in the registration order, and pass the supplied parameters to each listener.
Returns true if the event has a listener, otherwise false.

const event = require('events');
const myEmitter = new event.EventEmitter();
myEmitter.on('bear6',function first() {
    console.log('This is the first listener');
});
myEmitter.on('bear6',function second(arg1,arg2){
    console.log(`This is the second listener ${arg1},${arg2}`);
});
myEmitter.on('bear6',function third(...args){
    console.log(`This is the third listener ${args}`);
});
myEmitter.emit('bear6',1,2,3,4,5);

The results are as follows:

4, Error event

When an error occurs in the EventEmitter instance, the typical operation is to trigger the 'error' event. These are in node JS is considered a special case.
If EventEmitter does not register at least one listener for the 'error' event and the 'error' event is triggered, it will throw an error, print the stack trace, and then exit the node JS process.
To prevent node If the JS process crashes, a listener should always be added for the 'error' event.

const event = require('events');
const myEmitter = new event.EventEmitter();
myEmitter.on('error',function (err){
    console.error('this is error')
});
myEmitter.emit('error');

The error thrown during event processing can be captured using try... catch.

let EventEmitter = require('events').EventEmitter;
let emitter = new EventEmitter();

emitter.on('beep',function(){
    console.log('beep');
});
emitter.on('beep',function(){
    throw Error('oops!');
});
emitter.on('beep',function(){
    console.log('beep again');
});

console.log('before emit');
try{
    emitter.emit('beep');
}catch(err){
    console.error('caught while emitting:',err.message);
}
console.log('after emit');

It can be seen from the results that beep again is not printed, because after try... Catch... The catch receives and throws an error, and the listener behind the beep event error will not be started.

Keywords: node.js Front-end Back-end

Added by aufkes on Tue, 18 Jan 2022 12:36:18 +0200