SIGN IN

9. Node.js Lessons. Events, EventEmitter and Memory Leaks

Stay Informed

It's important to keep up
with industry - subscribe!

Stay Informed

Looks good!
Please enter correct name
Please enter correct email
Looks good!

16610_a6a5_3The next object we are interested in is EventEmitter, or, as it is sometimes called, EE. EventEmitter is a basic object that executes work with events in Node.js. A great number of other built-in objects generating events inherit from it. To use EventEmitter you only need to connect the built-in “events” module and take a respective property from it (let us create ee.js):

Right after that I can create the next object:

It has methods for working with events. The first one is subscription:

“оn” is an event name, “function” is a handler. I can list a lot of subscribers, and all of them will be called right in the same order how they’ve been appointed.
The second basic method is emit:

It generates events and transmits data. The data get delivered to a handler’s function. So, if we imagine that we write a web server, request handlers will be there in one place. A web server somehow uses it at your request:

And then, in another part of our code – for example, in a handler of incoming connections – there will be the emit server that generates events.
Let us activate this code:

As you can see, both events were handled. Initially – with the first handler, and then – with the second.
A more detailed description of various methods of work with events can be found in the documents, while we are going to talk about something that cardinally distinguishes the work with events in Node.js from the work with events in browsers. The first difference can be seen, if we look at this example:

While browser handlers work randomly, Node handlers work just exactly the way they were programmed to. It means, if I’ve got any handlers, by programming other handlers I am absolutely sure the latter will work after the former.
Another difference is that I can’t get a list of handlers with a certain appointed element in a browser. On the contrary, it is quite easy to do in Node.js: emitter.listeners(eventName) returns all handlers to this particular event. And emitter.listenerCount(eventName) enables you to get their overall number.
The next most critical difference is that the event having error as its name is handled in EventEmitter in a special way:

If emit of this event takes place somewhere and it doesn’t have a handler, EventEmitter will generate exclusions. As a result, such a minor and simple thing as emit will fail the whole process. The exclusions of a built-in type // throw TypeError will generate, if they look like this:

And if there is any object in the arguments, for example:

this object will be used as an argument // throw err. That’s how it works. For example, I launch this file (with the first variant – server.emit), and we all see that Node failed with an exclusion. If there is any handler, everything’s going to be ok:

If we transmit the object to emit in order to specify what kind of an error it was, the object will be delivered to a handler. And there we’ll be able to investigate it and undertake certain actions to handle it.

The last specification of EventEmitter we will talk about is a built-in solution to fight memory leaks. To analyze it we’ve got an example:

Here a new request-type object gets created and the current memory eating is outputted every 200 milliseconds. A request-type object – in real life it can be a client request – is an object with bigData field that contains something heavy in order to show you the amount of memory being eaten. Respectively, if there are many similar objects in the memory, they will eat a lot. Besides, the object has got a number of methods, too. We are not going to use them, but will see, what’s going on with memory, when a lot of similar objects suddenly appear.
So, get node leak.js started. You can easily notice how memory grows and then cleans up. Then grows and cleans up again. Right now everything’s good. That is a normal Node.js operation mode. For in this case, request is a local variable of the following function:

Once the function has its work done, it does not get saved. We do not need this object anymore, and the memory occupied by it can be cleaned up.
Let us expand our example a little bit. Add an object of the data source naming it db.

It can send some sort of information that request can, in its turn, send to a client:

The change is minor. But let us see what it will cause once the code gets activated. We see some kind of a Warning. The memory is constantly growing. What is the reason? To understand it, let us learn some details about EventEmitter logarithm – in particular, how these events work and what happens, when db.on data is requested. Information on the fact that I’ve installed a handler should be somewhere remembered. Indeed, it gets remembered in a special property of the db object. This property includes all event handlers that were selected. Whenever the emit request takes place, they are taken from it and get activated. Now we know why this leak has happened. Even though request is not necessary here anymore, this function still stays in the db object’s properties. As long as db exists, request will live, too. If db stays for a very long time, request will be there, too. You can see this with your own eyes by adding and launching the code once more.

console.log(db);

Stop! We’ve seen enough. Here is a db object and here is an events property, where handlers can be found:

And all the time it really gets bigger in size. Initially it was small, then a number of functions added. And every function being closed get followed by the whole request object.
We’ve also got warning in our console. In fact, EventEmitter has maximum number of handlers by default to be appointed. 10 of them in total. As soon as this number gets bigger, it outputs a warning that there can be a memory leak, which has actually happened in our case. So, what should we do? As one of our possible ways, we can move handlers to the data event, when handling is over. To do so, we need to re-write the code a little bit by adding a request of the end method, and this request is going to work well.

There is no any memory leak. When is this scenario the most dangerous one? In those cases, when for some reason the maximum number of handlers gets deactivated. So, they do a request

db.setMaxListeners(0);

and think that many people can subscribe for these events. Indeed, there are certain event sources with a great number of subscribers, and we need to cancel this limit. Respectively, they cancel the limit, but forget about handlers, which continue to stay there. This leads to Node’s expanding memory.
So, how can we control these leaks? It is quite a problem. The heapdump module, which enables us to take a shot of Node.js memory and then analyze it in Chrome, can help. But the best protection is to think what you’re doing by attaching objects with a short lifecycle to events with a long lifecycle. As well as remember about your future possible need to get unconnected from them in order to clean up your memory.
So, EventEmitter is one of the most important and widely used objects in Node.js. It is rarely used by itself. Descendants of this class are generally used – such as a request object, server object and others. We will learn something about it very soon. To generate an event also use the emit request:

emit(event,args…)->on(event, args…)

It gets event names and some arguments and data transmitted. At the same time, it activates handlers appointed via on.
EventEmitter guarantees that handlers will be requested in the same order. Thus, unlike browser handlers, you can always check out, whether there is any handler for a certain event. Moreover, the very emit method, if an event has been handled, returns true; otherwise it will be false. Anyway, this method is quite rarely used.
The EventEmitter has a special event that is called error:

emit(error) без обработчиков -> throw

If this event has no handlers, it leads to the fact that EventEmitter does throw by itself. But why? As we will see very soon, this decision is rather wise and practical because many built-in Node.js objects inform on their errors exactly this way, using emit(error). Even without this throw it would be rather easy to skip them, forget about them and then look for what has happened for a very long time.
Finally, EventEmitter has built-in solutions to fight memory leaks. Right now we don’t need them too badly, but later, when we do our project on Node.js, they will help us.

You can download lesson’s code from our repo.

n1JRsFeBMaterials for this lesson has taken from this screencast.

We are looking forward to meeting you on our website soshace.com

About the author

Stay Informed

It's important to keep up
with industry - subscribe!

Stay Informed

Looks good!
Please enter correct name
Please enter correct email
Looks good!

Related articles

The Path of the Self-Taught Programmer: Avoiding Common Problems

In this article, we’ll explore how a self-taught programmer comes to be: which education opportunities they can utilize, which problems they may>>>

Programming

Introduction to GitHub Desktop: A GUI Enhancement to a CLI Approach

In this article, we'll explore various use cases of GitHub Desktop -- GUI software designed to ehance your git workflow. Does it hold up against CLI>>>

Programming
29.10.2019

Python Array Explained and Visualized

In this tutorial, we’ll delve into how Python arrays work, what their limitations are, and how you can use them to maximize their>>>

Programming

Sign in

Forgot password?

Or use a social network account

 

By Signing In \ Signing Up, you agree to our privacy policy

Password recovery

You can also try to

Or use a social network account

 

By Signing In \ Signing Up, you agree to our privacy policy