Skip to main content

Handling and dispatching events with Node.js

Handling And Dispatching Events With Node.js

What is Node.js?

At its core, Node.js is an open-source runtime environment built for running JavaScript applications on the server side. It provides an event-driven, non-blocking (asynchronous) I/O and cross-platform runtime environment for building highly scalable server-side applications using JavaScript.
This is not going to be an introduction guide to Node.js; to learn more, you can check out the official docs or video tutorials on YouTube.

Modules in Node.js

Node.js comes with several modules — or libraries, as you can also call them — that can be included in your application and reused to help carry out specific tasks, such as the eventos, and pathmodules, as well as many more.
Some core modules in Node.js include:
ModuleDescription
httpMakes Node.js act like an HTTP server
urlParses and resolves URL strings
querystringHandles URL query strings
pathHandles file paths
fsHandles the file system
osProvides information about the operating system

Basic server setup

Requirements:

  • Node (the latest stable version)
  • npm (comes with Node on installation)
Let’s set up our Node server with the least configuration like below and save the file as index.js.
// index.js
const http = require('http');

// declare server variables
const hostname = '127.0.0.1';
const port = 8080;

const server = http.createServer((req, res) => {
  res.statusCode = 200;
  res.setHeader('Content-Type', 'text/plain');
  res.end('Hello World\n');
});

server.listen(port, hostname, () => {
  console.log(`Server is running at http://${hostname}:${port}/`);
});
Be sure to save the file and run node index.js. The output should be:
Server is running at http://127.0.0.1:8080
Every request to our server should give Hello World as the response.

The events module

The events module allows us to easily create and handle custom events in Node.js. This module includes the EventEmitter class, which is used to raise and handle the events.
Almost the whole of the Node.js core API is built around this module, which emits named events that cause function objects (also known as listeners) to be called. At the end of the article, we should have built a very simple module that implements the event module.

Some common properties and methods of the events module

EventEmitter methodsDescription
addListener(event, listener)Adds a listener to the end of the listeners array for the specified event. No checks are made to see if the listener has already been added.
on(event, listener)It can also be called as an alias of emitter.addListener()
once(event, listener)Adds a one-time listener for the event. This listener is invoked only the next time the event is fired, after which it is removed.
emit(event, [arg1], [arg2], […])Raise the specified events with the supplied arguments.
removeListener(event, listener)Removes a listener from the listener array for the specified event. Caution: changes array indices in the listener array behind the listener.
removeAllListeners([event])Removes all listeners, or those of the specified event.
The events object is required like any other module using the require statement and an instance created on the fly.
// index.js

const http = require('http');
const events = require('events');

// declare server variables
const hostname = '127.0.0.1';
const port = 8080;

//create an object of EventEmitter class from events module
const myEmitter = new events.EventEmitter();


const server = http.createServer((req, res) => {
  res.statusCode = 200;
  res.setHeader('Content-Type', 'text/plain');
  res.end('Hello World\n');
});

server.listen(port, hostname, () => {
  console.log(`Server running at http://${hostname}:${port}/`);
});
Let’s play around a little bit by listening to a custom event and at the same time dispatching the event:
//index.js

const http = require('http');
const events = require('events');

// declare server variables
const hostname = '127.0.0.1';
const port = 8080;

//create an object of EventEmitter class from events module
const myEmitter = new events.EventEmitter();

 //Subscribe for ping event
 myEmitter.on('ping', function (data) {
    console.log('First event: ' + data);
 });

 // Raising ping event
 myEmitter.emit('ping', 'My first Node.js event has been triggered.');

const server = http.createServer((req, res) => {
  res.statusCode = 200;
  res.setHeader('Content-Type', 'text/plain');
  res.end('Hello World\n');
});

server.listen(port, hostname, () => {
  console.log(`Server running at http://${hostname}:${port}/`);
});
For the changes to reflect, the server must be restarted. Once done, refresh the page in the browser, and you should see a message logged in the console:
First event: My first Node.js event has been triggered.
As seen in the example above, aside from triggering the event, we can also pass along information as a second parameter to the listener.

Handling events only once

As we did above, when a listener is registered using the emitter.on() method, that listener will be invoked every time the named event is emitted. But for some reason, some events should only be handled once throughout the application lifecycle and can be achieved with the once() method.
Let’s add this to our code:
//index.js

const http = require('http');
const events = require('events');

// declare server variables
const hostname = '127.0.0.1';
const port = 8080;

//create an object of EventEmitter class from events module
const myEmitter = new events.EventEmitter();

//Subscribe for ping event
 myEmitter.on('ping', function (data) {
    console.log('First event: ' + data);
 });

 // Raising ping event
 myEmitter.emit('ping', 'My first Node.js event has been triggered.');

let triggered = 0;
myEmitter.once('event', () => {
  console.log(++triggered);
});
myEmitter.emit('event');
// Prints: 1
myEmitter.emit('event');
// Ignored


const server = http.createServer((req, res) => {
  res.statusCode = 200;
  res.setHeader('Content-Type', 'text/plain');
  res.end('Hello World\n');
});

server.listen(port, hostname, () => {
  console.log(`Server running at http://${hostname}:${port}/`);
});
By using the once() method instead of on(), the event cannot happen more than once and would only be triggered on first occurrence. If it’s being fired the second time during the program, it will be ignored.

Error events

Errors during development are inevitable but can be handled properly in Node.js. Apart from the try-catch block, Node can also listen to an error event and carry out several actions whenever an error occurs. If an EventEmitter does not have at least one listener registered for the error event, and an error event is emitted, the error is thrown, a stack trace is printed, and the Node.js process exits.
//index.js

const http = require('http');
const events = require('events');

// declare server variables
const hostname = '127.0.0.1';
const port = 8080;

//create an object of EventEmitter class from events module
const myEmitter = new events.EventEmitter();

//Subscribe for ping event
 myEmitter.on('ping', function (data) {   
 console.log('First subscriber: ' + data);
 });

 // Raising ping event
myEmitter.emit('ping', 'This is my first Node.js event emitter example.');

let triggered = 0;
myEmitter.once('event', () => {
  console.log(++triggered);
});
myEmitter.emit('event');
// Prints: 1
myEmitter.emit('event');
// Ignored

myEmitter.on('error', (err) => {
  console.error('whoops! there was an error bro!' + err);
 });
myEmitter.emit('error', new Error('whoops!'));
 // Prints: whoops! there was an error to the console

const server = http.createServer((req, res) => {
  res.statusCode = 200;
  res.setHeader('Content-Type', 'text/plain');
  res.end('Hello World\n');
});

server.listen(port, hostname, () => {
  console.log(`Server running at http://${hostname}:${port}/`);
});
To prevent against crashing the Node.js process, it is recommended that listeners should always be added for the 'error' events.

Conclusion

We have learned a lot about events and how it plays a big role in the development of Node.js applications. We also learned how to create, dispatch, and manage events. With event-driven programming, code is written to react instead of waiting to be called.

Comments

Popular posts from this blog

How to use Ngx-Charts in Angular ?

Charts helps us to visualize large amount of data in an easy to understand and interactive way. This helps businesses to grow more by taking important decisions from the data. For example, e-commerce can have charts or reports for product sales, with various categories like product type, year, etc. In angular, we have various charting libraries to create charts.  Ngx-charts  is one of them. Check out the list of  best angular chart libraries .  In this article, we will see data visualization with ngx-charts and how to use ngx-charts in angular application ? We will see, How to install ngx-charts in angular ? Create a vertical bar chart Create a pie chart, advanced pie chart and pie chart grid Introduction ngx-charts  is an open-source and declarative charting framework for angular2+. It is maintained by  Swimlane . It is using Angular to render and animate the SVG elements with all of its binding and speed goodness and uses d3 for the excellent math functio...

Understand Angular’s forRoot and forChild

  forRoot   /   forChild   is a pattern for singleton services that most of us know from routing. Routing is actually the main use case for it and as it is not commonly used outside of it, I wouldn’t be surprised if most Angular developers haven’t given it a second thought. However, as the official Angular documentation puts it: “Understanding how  forRoot()  works to make sure a service is a singleton will inform your development at a deeper level.” So let’s go. Providers & Injectors Angular comes with a dependency injection (DI) mechanism. When a component depends on a service, you don’t manually create an instance of the service. You  inject  the service and the dependency injection system takes care of providing an instance. import { Component, OnInit } from '@angular/core'; import { TestService } from 'src/app/services/test.service'; @Component({ selector: 'app-test', templateUrl: './test.component.html', styleUrls: ['./test.compon...

How to solve Puppeteer TimeoutError: Navigation timeout of 30000 ms exceeded

During the automation of multiple tasks on my job and personal projects, i decided to move on  Puppeteer  instead of the old school PhantomJS. One of the most usual problems with pages that contain a lot of content, because of the ads, images etc. is the load time, an exception is thrown (specifically the TimeoutError) after a page takes more than 30000ms (30 seconds) to load totally. To solve this problem, you will have 2 options, either to increase this timeout in the configuration or remove it at all. Personally, i prefer to remove the limit as i know that the pages that i work with will end up loading someday. In this article, i'll explain you briefly 2 ways to bypass this limitation. A. Globally on the tab The option that i prefer, as i browse multiple pages in the same tab, is to remove the timeout limit on the tab that i use to browse. For example, to remove the limit you should add: await page . setDefaultNavigationTimeout ( 0 ) ;  COPY SNIPPET The setDefaultNav...