Node Event Emitters — For Beginners and Experts

Everything you need to know about event emitters in Node.js

Kunal Tandon
Nov 15, 2019 · 7 min read

The core of NodeJS is event-driven programming. In NodeJS, we achieve event-driven programming with the event-emitter class.

Image for post
Image for post

In this article, we’ll discuss everything about the event-emitter class. The following are the topics that I’ll be covering in this article.

  • What is an event emitter?
  • Creating an event emitter
  • Attaching event listeners and publishing events to an event emitter
  • Maintaining a single event-emitter instance applicationwide
  • Is it synchronous or asynchronous?
  • Order of execution of event emitters
  • How and where NodeJS internally uses event emitters
  • Some useful member functions of the event-emitter class
Visit https://knowledgescoops.com for more such articles

Event Emitters

EventEmitter is a class that helps us create a publisher-subscriber pattern in NodeJS.

With an event emitter, we can simply raise a new event from a different part of an application, and a listener will listen to the raised event and have some action performed for the event.

Creating an Event Emitter

To create an event emitter, we need to create an instance of the event emitter instance from the events module in NodeJS.

Note: I’m using Typescript instead of JavaScript.

import { EventEmitter } from 'events';const eventEmitter = new EventEmitter();

This will create an EventEmitter instance. But what do we do with it? Let's see it in action.

Publishing Events and Listening to Them

The EventEmitter class comes with a lot of member functions. We’ll be using these member functions to publish events and listen to them.

Below are the member functions in the EventEmitter class.

Image for post
Image for post
EventEmitter’s member functions

For now, we’ll only pay attention to these two member functions:

  • on(eventName, …)
  • emit(eventName, …)

To publish an event, we use the emit() function, and to listen to an event, we use the on() function.

In EventEmitters, we publish and listen to the events by name.

In the last code snippet, where we created an EventEmitter object, we use the following code to raise events and listen to them.

Running the above code snippet prints the following output in the console:

> Data Received

In the above code snippet, we raised an event with the name myEvent on the last line, and we had a listener registered to the event just above the line of the publishing event.

At the time of publishing the event, there must be an EventEmitter listener existing to listen to the published event.

For example, if we change the above code snippet to …

… the output will be:

> Listener 1

We get only Listener 1 as output in the console, as the Listener 2 was registered after emitting the event.

EventEmitter Instance Should Be Singleton for a Single Event Name

In other words, the on() and the emit() functions must be called on the same EventEmitter instance.

The listeners won’t work if registered on a separate EventEmitter instance.

This won’t print anything in the console, as there were two separate instances used in this code: one instance for registering the publisher and the other instance for listening to the event.

Maintaining a Single Event-Emitter Instance Applicationwide

A node application is generally 100s of files. This gets challenging to maintain by a single copy of the EventEmitter instance throughout the application.

There is a simple strategy to create and maintain a singleton copy for an EventEmitter instance.

When creating the EventEmitter instance, we can simply store it as an application-level setting using app.set(<key>, <value>).

Is an Event Emitter Synchronous or Asynchronous?

Consider the following code snippet:

When we execute this code snippet, we get the following output in the console:

> Statement A
> Statement B
> Statement C

The events raised by event emitters are synchronously executed by the listeners in the current event loop’s iteration.

Note: If you want to read more about event loops and how synchronous and asynchronous code runs in NodeJS, read the following article.

Order of Execution of the Listeners

The listeners are executed in the order the listeners are created for an event emitter.

Consider the following code snippet to understand this statement:

When executed, the above code gives the output:

> Statement A
> Emitted Statement - FIRST
> Emitted Statement - SECOND
> Statement B

The listener that’s registered earlier is executed earlier.

How and Where NodeJS Internally uses Event Emitters

NodeJs internally uses event emitters widely across its environment. The first example we can think of is streams.

Streams extend event emitters. Streams are built on top of event emitters that raise predefined events like open, end, data, etc.

The following code snippet is a simple example of a stream — explaining the resemblance with event emitters.

When executed, the code will give the following output:

Started Reading...Chunk: 1
----------------------------------------------------------
<Buffer 4c 6f 72 65 6d 20 69 70 73 75 6d 20 64 6f 6c 6f 72 20 73 69 74 20 61 6d 65 74 2c 20 63 6f 6e 73 65 63 74 65 74 75 72 20 61 64 69 70 69 73 63 69 6e 67 ... >
Chunk: 2
----------------------------------------------------------
<Buffer 74 20 6e 75 6e 63 20 76 69 74 61 65 20 66 65 72 6d 65 6e 74 75 6d 2e 20 49 6e 20 75 74 20 61 72 63 75 20 74 65 6d 70 6f 72 2c 20 66 61 75 63 69 62 75 ... >
Chunk: 3
----------------------------------------------------------
<Buffer 20 76 69 74 61 65 2c 20 65 67 65 73 74 61 73 20 69 64 20 73 65 6d 2e 20 44 6f 6e 65 63 20 75 74 20 75 6c 74 72 69 63 69 65 73 20 6c 6f 72 65 6d 2c 20 ... >
Completed Reading...

data.txt is a large text file containing some random lorem-ipsum text

Notice here the listeners are called internally by NodeJS. We don’t need to call the listeners explicitly as NodeJS internally extends event emitters, exposes custom predefined events (data, open, end), and raises these events automatically when required for the streams.

In the data listener, the buffer gets printed instead of the string since NodeJS, instead of reading the text content of the file, actually reads the file as a buffer.

Another example of NodeJS using event emitters is the global process variable.

The process object exposes some variables we can listen to and respond to accordingly. These events are:

process.on(‘exit’)
process.on(‘uncaughtException’)

The following is an example showing their usage:

process.on("exit", () => console.log("Exit"));
process.on("beforeExit", () => console.log("Before Exit"));
process.on('uncaughtException', () => {
console.log('Exception');
process.exit();
});
throw new Error('Test Error');

Running the above code will print the following output in the console:

Exception
Exit

Some Useful Member Functions of the EventEmitter Class

In the EventEmitter class, we have only looked at the .on() and the .emit() function. But there are other member functions available in the EventEmitter class.

The following is the list of all the member functions available in the EventEmitter class.

Image for post
Image for post
EventEmitter’s member functions

We’ll cover some of the useful member functions among them.

once()

With once(), the listener will be discarded after listening for an event. Events listened with once() will be triggered only once.

Running the above code will give the output:

Emitted Statement - ON
Emitted Statement - ONCE
Emitted Statement - ON
Emitted Statement - ON

Notice here the once listener was only called once. After getting called for the first time, it’ll be discarded for further use.

eventNames()

Get all the active event names.

Running the following code will give the output:

[ 'myEvent', 'myEvent2', 'myEvent3' ]
EVENT - ONCE
[ 'myEvent', 'myEvent2' ]

Notice after the once event gets triggered, calling eventNames() doesn’t give its event name.

addListener()

It’s exactly the same as on(). It’s just an alias for event.on().

removeListener()

This is used to remove a listener.

Running the above code will give the output as:

[ 'myEvent', 'myEvent2' ]
[ 'myEvent2' ]

To remove a listener, we need to pass the same function reference in the second parameter that was used to create a listener.

removeAllListeners()

This is used to remove all active event listeners from an EventEmitter instance.

Running the following code will give the output as an empty array:

[]

Conclusion

That’s all there is about event emitters in NodeJS. I tried covering all the important topics in this article. Let me know in the response section if I missed one.

For more such articles, visit www.knowledgescoops.com

Want to read more articles like this?
Follow me on medium @kunaltandon.kt
Connect with me on LinkedIn:
https://www.linkedin.com/in/kunal-tandon/

Developer’s Arena

An arena for the developers in the city

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store