Tutorials

Soft Skills

Event Loop & Event Emitters in Node.js

We has started this tutorial series by saying that NodeJS is extremely fast. But have you thought why is this so? Even after being a single threaded environment, it beats python and ruby frameworks by many times. This article tries to explain why this is. What makes JavaScript fast…!! So hold on.

Event Loop

Event loop is loop in NodeJS environment which runs in background checking for various events and callback functions to execute. Understand it this way.

Assume NodeJS is the name of a restaurant. You are the client and you enter the restaurant and get seated. A waiter comes to you and asks what you want. You ask him for a bottle of water, one pasta and one pizza. The waiter will then tell other servers what to do. He will tell one server to get a bottle of water, one chef to cook pasta and another chef to cook pizza. If no one is free then the command is queued with the respective person. After taking this order he goes to other customer and takes their order.

The server who went to fetch a bottle of water comes back and informs the waiter that he is done and waits for the waiter to finish taking the current order. Then he hands over the bottle to the waiter who delivers it to you. Meanwhile the pasta is still being cooked and pizza is ready to server. The chef informs the waiter about the pizza and he delivers the pizza freeing up the pizza chef. Finally the pasta is finished and passed on to the waiter. When all the servers and chefs are finished with their work AND no more clients are to come, the restaurant is shut down.

This is how this will look like

In a similar way when a client connects to a NodeJS process, the process is greeted by the main thread (manager) which takes all the functions and assigns them worker threads as required. If no worker thread is available, then the request is queued till a worker thread is available to process the request. NodeJS architecture has a set of worker threads in its internal thread pool (size can be changed) to handle blocking tasks in the background while the main thread is interacting with the clients.

While the many worker threads are doing their function, another thread, the event loop, runs in background scanning all the worker threads for their result. If a particular worker thread has finished executing, then the callback function passed to the worker thread is called by the event loop which may again transfer the function to another worker thread, or if no callbacks are left then the output is produced.

Once a worker thread has finished executing, the thread is killed and sent back to the internal thread pool for reuse by some other function. The event loop while scanning for the results also keeps track of the number of threads in use. If no worker thread is being used and the main thread has stopped receiving any input, the the Node process is terminated.

Since the thread which is interacting with the clients is not involved in any processing, the number of clients a NodeJS server can accept is much higher than traditional Apache, Ruby on Rails or Django servers.

Events

In the previous section we talked about how the event loop keeps scanning the worker thread for results. But how exactly does the event loop know when a result has been produced? The answer is events. Events are building blocks of NodeJS architecture which was developed as an event-driven server structure.

Events are some changes or signals which are emitted by the worker threads to let the event loop know that a particular event has occurred. In the above restaurant example events can be imagined as a mechanism by which the chef and servers are signalling the waiter that their job is finished.

An algorithm for the event loop can be simplified as:

Listen for any calls (events)

If any thread is calling then attend the thread.

Process the result

Go to step 1

Algorithm for our waiter:

Manager assigns a waiter to listen to “bottle”, “pasta” and “pizza” events

Scan for events

If no event, go to step 2

waiter on “bottle” event

Fetch the bottle

Serve it to the client

waiter on “pasta” event

Server pasta to the client

waiter on “pizza” event

Slice the pizza

Serve it to the client

Go to step 2

One problem which algorithm is that even after the events are done, the waiter still keeps listening to events. To solve this the manager needs to tell the waiter to stop listening to particular events.

Create a new index.js file in your project directory with the following lines

This simple code is to demonstrate the functioning of events in NodeJS. To use events in NodeJS we need to use the b>events module, a core NodeJS module, to listen and emit events. From the events module, we need specifically EventEmitter object which will handle the events for us.

We define two different functions - doorKnockListener & phoneRingListener, which are the functions to be executed when a particular event is captured by the event loop. After declaring the listener functions, we need to assign these functions to particular events so that the event loop can trigger the right functions for the right events.

We add listeners to events using emitter.addListener(eventName, callback) where the eventName is an alphanumeric string. Here we make doorKnockListener function to react to door event and phoneRingListener to execute on phone event. Note that events are CASE SENSITIVE - Door event is not the same as door event.

Finally there would be something that would actually emit this event. So we emit the door event.

The output

As you can see, on emitting the door event, the doorKnockListener is called and executed. Since the phone event was not emitted hence the phoneRingListener is never executed.

Once the event is emitted and executed, the event loop still keeps listening for these events until you remove the listener. See the example below.

After the door event is emitted for the first time (line 17), the event loop still listens for the event. So when the door event is emitted again in line 19, again the doorKnockListener is called. The listener is removed in the next line using emitter.removeListener(eventName, callback) and then if the event is emitted, the callback function is not executed.

You can even attach multiple listeners for the same event. Try changing the code of index.js as (see line no.s for change)

Here we assign phoneRingListener and doorKnockListener to the same door event.

When the door event is emitted, both the listeners are called in the order of assigment.

There are many uses of events in NodeJS apart from internal events. For example, the process global object emits and listens to many useful events like: