Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to use the EventEmitter module in Node.js

2025-03-26 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/02 Report--

This article mainly explains "how to use the EventEmitter module in Node.js". Interested friends may wish to have a look. The method introduced in this paper is simple, fast and practical. Now let the editor take you to learn how to use the EventEmitter module in Node.js.

The use of EventEmitter

EventEmitter provides us with an event subscription mechanism, which is used by introducing the events module.

Const {EventEmitter} = require ("events"); const eventEmitter = new EventEmitter (); / / listen for data event eventEmitter.on ("data", () = > {console.log ("data");}); / / trigger data event eventEmitter.emit ("data")

In the above code, we use the on method to bind the callback function for the event and the emit method to trigger an event.

On 、 addListener

We can add a listener to an event through the on and addListener methods, both of which are used the same way

EventEmitter.on ("data", () = > {console.log ("data");}); eventEmitter.addListener ("data", () = > {console.log ("data");})

The first parameter is the event name, and the second parameter is the corresponding callback function, which is called when the EventEmitter instance object calls emit to trigger the corresponding event, as shown in

Const {EventEmitter} = require ("events"); const eventEmitter = new EventEmitter (); eventEmitter.on ("data", () = > {console.log ("data");}); eventEmitter.addListener ("data", () = > {console.log ("data");}); eventEmitter.emit ("data")

Data will be printed out twice in the console.

Datadata

As you can see from the above example, you can bind multiple callback functions for the same event.

Execution sequence

When multiple callback functions are bound using on or addListener, the order in which they are triggered is the order in which they are added, as shown in

Const {EventEmitter} = require ("events"); const eventEmitter = new EventEmitter (); eventEmitter.on ("data", () = > {console.log ("data 1");}); eventEmitter.on ("data", () = > {console.log ("data 2");}); eventEmitter.on ("data", () = > {console.log ("data 3");}); eventEmitter.emit ("data")

Will print out in turn on the console

Data 1data 2data 3 is added repeatedly

And when you bind an event using the on method, there is no de-recheck.

Const {EventEmitter} = require ('events'); const eventEmitter = new EventEmitter (); const listener = () = > {console.log ("lsitener");} eventEmitter.on ("data", listener); eventEmitter.on ("data", listener); eventEmitter.emit ("data")

The print result of the console is

Lsitenerlsitener

The above program binds the listener function twice for the event, but internally does not check whether the callback function has been added and then deduplicates it, so the above prints out the listener twice on the console.

Transfer parameters

In addition, the callback function can also receive parameters, which are passed in when the event is triggered by emit, such as

Const {EventEmitter} = require ("events"); const eventEmitter = new EventEmitter (); eventEmitter.on ("data", data = > {console.log (data);}); / / pass the parameter HelloWorldkeeper eventEmitter.emit ("data", "HelloWorld!") to the callback function

When we use emit to trigger the event above, we also pass an additional parameter, which is passed to the callback function.

Synchronous execution

Another concern is whether the event is triggered synchronously or asynchronously. Let's do an experiment.

Const {EventEmitter} = require ("events"); const eventEmitter = new EventEmitter (); eventEmitter.on ("data", () = > {console.log ("data event triggered!") ); console.log ("start"); eventEmitter.emit ("data"); console.log ("end")

Above, we print information to the console before and after triggering the event. If the event is executed asynchronously, then the subsequent print statement will be executed first, otherwise, if it is synchronous, the callback function bound by the event will be executed first. The execution result is as follows

Start triggered the data event! End

It can be seen that the event trigger is executed synchronously.

Off 、 removeListener

The function of off and removeListener methods is opposite to that of on and addLsitener. Their function is to delete the corresponding callback function for an event.

Const {EventEmitter} = require ('events'); const eventEmitter = new EventEmitter (); let listener1 = () = > {console.log ("listener1");} let listener2 = () = > {console.log ("listener2");} eventEmitter.on ("data", listener1); eventEmitter.on ("data", listener2); / / whether the two callback functions execute eventEmitter.emit ("data"); eventEmitter.off ("data", listener1) when triggered for the first time / / the second trigger will only execute listener2eventEmitter.emit ("data")

The console prints the result as

Listener1listener2listener2

The first time an event is triggered, both events are triggered, and then we remove the callback function listener1 for the event, so the second time it is triggered, only listener2 will be triggered.

Note: if we use on or addListener to bind an anonymous function, we cannot unbind a callback function through off and removeListener because it will unbind the function by comparing whether the references of the two functions are the same.

Once

Using once, you can bind a callback function that is executed only once. When triggered once, the callback function will be unbound automatically.

Const {EventEmitter} = require ("events"); const eventEmitter = new EventEmitter (); eventEmitter.once ("data", () = > {console.log ("data");}); eventEmitter.emit ("data"); eventEmitter.emit ("data")

In the above code, we use once to bind a callback function for the data event, and then use the emit method to trigger it twice, because the callback function bound with once will only be triggered once, so the callback function will not be executed the second time, so the data is printed only once on the console.

In addition, like the callback function bound by on, we can also pass parameters to the callback function through the emit method.

Const {EventEmitter} = require ("events"); const eventEmitter = new EventEmitter (); eventEmitter.once ("data", data = > {console.log (data);}); eventEmitter.emit ("data", "Hello")

Console print results

HelloprependListener 、 prependOnceListener

Callback functions bound with on or addListener for events are executed according to the order in which they are added, while event callback functions bound with prependLsitener are executed before other callback functions

Const {EventEmitter} = require ('events'); const eventEmitter = new EventEmitter (); eventEmitter.on ("data", () = > {console.log ("on");}); eventEmitter.prependListener ("data", () = > {console.log ("prepend");}); eventEmitter.emit ("data")

The printing result of the above generation we first use the console is

Prependon

PrependOnceListener is the same as prependListener, but the callback function bound to it will only be executed once

Const {EventEmitter} = require ('events'); const eventEmitter = new EventEmitter (); eventEmitter.on ("data", () = > {console.log ("on");}); eventEmitter.prependOnceListener ("data", () = > {console.log ("prepend once");}); eventEmitter.emit ("data"); eventEmitter.emit ("data")

Above we bound a callback function using prependOnceListener. When the event is triggered, the callback function will be executed before other functions and will only be executed once, so when we trigger the function the second time, the callback function will not be executed, and the console prints the result as

Prepend onceononremoveAllListeners

The removeAllListeners ([event]) method can delete all callback functions bound to the event event. If no event parameter is passed in, this method will delete all callback functions bound to the event.

Const {EventEmitter} = require ('events'); const eventEmitter = new EventEmitter (); eventEmitter.on ("data", () = > {console.log ("data 1");}); eventEmitter.on ("data", () = > {console.log ("data 2");}); eventEmitter.emit ("data"); eventEmitter.removeAllListeners ("data"); eventEmitter.emit ("data")

The above program binds two callback functions for the data event, and triggers a data event before calling the removeAllListeners method. When the data event is triggered the second time, no callback function is executed. RemoveAllListeners removes all callback functions bound to the data event. The print result of the console is as follows:

Data 1data 2eventNames

Through the eventNames method, we can know which events are bound to the callback function, which returns an array

Const {EventEmitter} = require ("events"); const eventEmitter = new EventEmitter (); eventEmitter.on ("start", () = > {console.log ("start");}); eventEmitter.on ("end", () = > {console.log ("end");}); eventEmitter.on ("error", () = > {console.log ("error");}); console.log (eventEmitter.eventNames ()) / / ['start',' end', 'error']

If we delete all callback functions for an event, eventNames will not return the event at this time

EventEmitter.removeAllListeners ("error"); console.log (eventEmitter.eventNames ()); / / ['start',' end'] listenerCount

The listenerCount method can get how many callback functions are bound to an event.

Const {EventEmitter} = require ("events"); const eventEmitter = new EventEmitter (); eventEmitter.on ("data", () = > {}); eventEmitter.on ("data", () = > {}); console.log (eventEmitter.listenerCount ("data")); / / 2setMaxLsiteners, getMaxListeners

SetMaxListeners is used to set the maximum number of callback functions bound for each event, but you can actually bind more callback functions than the set number. However, when you bind more than a specified number of callback functions, you will give a warning on the console.

Const {EventEmitter} = require ("events"); const eventEmitter = new EventEmitter (); / / sets that only one callback function eventEmitter.setMaxListeners (1) can be bound for each callback function; / / three callback functions eventEmitter.on ("data", () = > {console.log ("data 1");}); eventEmitter.on ("data", () = > {console.log ("data 2");}) EventEmitter.on ("data", () = > {console.log ("data 3");})

Run the above program, and the console prints the result as

Data 1data 2data 3 (node:36928) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 2 data listeners added to [EventEmitter]. Use emitter.setMaxListeners () to increase limit

It can be seen that all three callback functions bound by the event can be triggered, and a warning message is printed on the console.

GetMaxListeners is a method to get how many callback functions can be bound for each event. When using the value set by setMaxListeners, the value returned is the same.

Const {EventEmitter} = require ("events"); const eventEmitter = new EventEmitter (); eventEmitter.setMaxListeners (1); console.log (eventEmitter.getMaxListeners ()); / / 1

If you do not use setMaxLsiteners to set it, you can bind up to 10 callback functions for each event by default, which can be obtained through the defaultMaxListeners property of EventEmitter

Const {EventEmitter} = require ("events"); console.log (EventEmitter.defaultMaxListeners); / / 10listeners, rawListeners

When we bind a callback function using once, we do not bind the function directly for the event. Instead, we use a function to wrap the function, which is called wrapper, and then bind the wrapper function for the event. Inside the wrapper function, we set the logic to unbind ourselves after one execution.

Listeners returns an array of callback functions bound to the specified event, while rawListeners is also an array of callback functions that return the specified event binding. Unlike listeners, the callback function bound to once returns wrapper rather than the native bound function.

Const {EventEmitter} = require ("events"); const eventEmitter = new EventEmitter (); eventEmitter.once ("data", () = > {console.log ("once");}) let fns = eventEmitter.listeners ("data"); / / the function bound by once, not wrapper, has no internal unbinding logic, so the once bound function fns [0] () eventEmitter.emit ("data") will be executed when the data event is triggered later.

The console prints the result as

Onceonce

Next, replace the above listeners with rawListeners

Const {EventEmitter} = require ("events"); const eventEmitter = new EventEmitter (); eventEmitter.once ("data", () = > {console.log ("once");}) let fns = eventEmitter.rawListeners ("data"); / / because the wrapper of the once binding function is returned, it has logic to unbind after executing once, so the once bound function will no longer execute fns [0] () eventEmitter.emit ("data") when the event is triggered later.

The print result of the console is

Once implements an EventEmitter

In this section, you will implement an EventEmitter from scratch to deepen your understanding of the module. First, we need to prepare a listeners to store all the bound callback functions, which is a Map object, the key is the event name, and the value is an array, which holds the callback function bound to the event.

Class EventEmitter {constructor () {this.listeners = new Map ();}} on, addListener

When using on to bind the callback function, we first determine whether there is a callback function bound for this event in the Map collection. If there is a corresponding array, add the callback function to the array, if not, create a new array, add the callback function, and add it to the Map collection.

On (event, callback) {if (! this.listeners.has (event)) {this.listeners.set (event, []);} let fns = this.listeners.get (event); fns.push (callback);}

The function of addListener is the same as that of on. We can call the on method directly.

AddListener (event, callback) {this.on (event, callback);} emit

When we use emit to trigger events, we fetch an array of corresponding callback functions from Map, and then fetch the functions for execution in turn. In addition, we can also pass parameters through emit

Emit (event,... args) {if (! this.listeners.has (event)) {return;} let fns = this.listeners.get (event); let values = []; for (let fn of fns) {values.push (fn);} for (let fn of values) {fn (.ARGs);}}

Here you may think that my writing is a little complicated, so you will think it is better to write it this way.

Emit (event,... args) {if (! this.listeners.has (event)) {return;} for (let fn of fns) {fn (.args);}}

That's what I wrote at first, but because the once-bound function removes itself from the array after execution and is synchronized, the array is constantly changing when the loop is executed, and using the above method will cause some callback functions to be missed, so I first copy the functions in the array to another array, and then iterate through the new array. Because the functions bound by once will only delete the functions in the original array, not the new array, the length of the new array will not change during traversal, and there will be no omission that the function is not executed.

PrependListener

The logic for implementing prependListener is the same as on, except that we add a callback function to the front of the array

PrependListener (event, callback) {if (! this.listeners.has (event)) {this.listeners.set (event, []);} let fns = this.listeners.get (event); fns.unshift (callback);} off, removeListener

The off method is used to unbind the event. Find the specified function in the array and delete it.

Off (event, callback) {if (! this.listeners.has (event)) {return;} let fns = this.listeners.get (event); / / find the callback function in the array, and then delete for (let I = 0; I)

< fns.length; i++) { if(fns[i] === callback) { fns.splice(i, 1); break; } } // 如果删除回调函数后,数组为空,则删除该事件 if (fns.length === 0) { this.listeners.delete(event); }} removeListener 同 off 的作用一样,我们在内部直接调用 off 方法即可 removeListener(event, callback) { this.off(event, callback);}once、prependOnceListener 使用 once 绑定一个只执行一次的函数,所以我们需要将绑定的回调函数使用一个函数包装一下,然后添加进数组中,这个包装函数我们称之为 wrapper。在包装函数中,当执行一遍后会将自己从数组中删除 once(event, callback) { let wrapper = (...args) =>

{callback (.args); this.off (event, wrapper);} if (! this.listeners.has (event)) {this.listeners.set (event, []);} let fns = this.listeners.get (event); fns.push (wrapper);}

The implementation of prependOnceListener is the same as once, except that you can insert a function into the beginning of the array and replace the push in the above code with unshift.

PrependOnceListener (event, callback) {let wrapper = (... args) = > {callback (.args); this.off (event, wrapper);} if (! this.listeners.has (event)) {this.listeners.set (event, []);} let fns = this.listeners.get (event); fns.unshift (wrapper);} removeAllListeners

Delete the corresponding events directly. If no specific events are passed in, you need to delete all the events.

RemoveAllListeners (event) {/ / if no event is passed in, delete all events if (event = undefined) {this.listeners = new Map (); return;} this.listeners.delete (event);} eventNames

Get which events have been bound

EventNames () {return [... this.listeners.keys ()];} listenerCount

Get how many callback functions can be bound to an event

ListenerCount (event) {return this.listeners.get (event) .length;}

The above implementation has a bug, that is, functions bound with once cannot be deleted. My idea is to use a Map to correspond the functions bound by once to the corresponding wrapper. When deleting, you can find the corresponding wrapper according to the callback function of once and delete it.

Constructor () {this.listeners = new Map (); / / Save the callback function of once and the corresponding wrapper this.onceToWrapper = new Map ();} once (event, callback) {let wrapper = (... args) = > {callback (.ARGs); / / delete the relationship between callback and wrapper this.onceToWrapper.delete (callback); this.off (event, wrapper) } if (! this.listeners.has (event)) {this.listeners.set (event, []);} let fns = this.listeners.get (event); / / before adding, bind the relationship between callback and wrapper this.onceToWrapper.set (callback, wrapper); fns.push (wrapper);} prependOnceListener (event, callback) {let wrapper = (... args) = > {callback (... args) / / Ibid. This.onceToWrapper.delete (callback); this.off (event, wrapper);} if (! this.listeners.has (event)) {this.listeners.set (event, []);} let fns = this.listeners.get (event); / / Ibid this.onceToWrapper.set (callback, wrapper); fns.unshift (wrapper) } off (event, callback) {if (! this.listeners.has (event)) {return;} let fns = this.listeners.get (event); / / find whether there is a corresponding wrapper in onceToWrapper, if there is a description of callback = this.onceToWrapper.get (callback) bound by once | | callback; for (let I = 0; I)

< fns.length; i++) { if(fns[i] === callback) { fns.splice(i, 1); break; } } if (fns.length === 0) { this.listeners.delete(event); }} 全部代码如下 class EventEmitter { constructor() { this.listeners = new Map(); this.onceToWrapper = new Map(); } on(event, callback) { if(!this.listeners.has(event)) { this.listeners.set(event, []); } let fns = this.listeners.get(event); fns.push(callback); } addListener(event, callback) { this.on(event, callback); } emit(event, ...args) { if(!this.listeners.has(event)) { return; } let fns = this.listeners.get(event); let values = []; for(let fn of fns) { values.push(fn); } for (let fn of values) { fn(...args); } } prependListener(event, callback) { if(!this.listeners.has(event)) { this.listeners.set(event, []); } let fns = this.listeners.get(event); fns.unshift(callback); } off(event, callback) { if(!this.listeners.has(event)) { return; } let fns = this.listeners.get(event); callback = this.onceToWrapper.get(callback) || callback; for (let i = 0; i < fns.length; i++) { if(fns[i] === callback) { fns.splice(i, 1); break; } } if (fns.length === 0) { this.listeners.delete(event); } } removeListener(event, callback) { this.off(event, callback); } once(event, callback) { let wrapper = (...args) =>

{callback (.args); this.onceToWrapper.delete (callback); this.off (event, wrapper);} if (! this.listeners.has (event)) {this.listeners.set (event, []);} let fns = this.listeners.get (event); this.onceToWrapper.set (callback, wrapper) Fns.push (wrapper);} prependOnceListener (event, callback) {let wrapper = (... args) = > {callback (.args); this.onceToWrapper.delete (callback); this.off (event, wrapper);} if (! this.listeners.has (event)) {this.listeners.set (event, []) } let fns = this.listeners.get (event); this.onceToWrapper.set (callback, wrapper); fns.unshift (wrapper);} removeAllListeners (event) {if (event = = undefined) {this.listeners = new Map (); return;} this.listeners.delete (event) } eventNames () {return [... this.listeners.keys ()];} listenerCount (event) {return this.listeners.get (event) .length;}} so far, I believe you have a better understanding of "how to use the EventEmitter module in Node.js". You might as well do it in practice! Here is the website, more related content can enter the relevant channels to inquire, follow us, continue to learn!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report