Deeper Dive Into Node.js: Part Two
The second part in a two-part series about Node.js.
In part one I covered the structure of Node.js library and talked a bit about modules. Today, I want to dive deeper into modules for Node.js and how to use custom and contrib modules while building your web applications using the library.
Node.js Module System
In the Node.js module system, each file is treated as a separate module. For example, geometry.js can be a module that is required for the definition and calculation of the properties of geometrical objects.
Variables defined in the module file are local to the module and will be private. The privacy is achieved because before a module's code is executed, Node.js will wrap it with a function wrapper:
(function(exports, require, module, __filename, __dirname) {
// Module code lives in here.
});
This is done automatically by the library. If you’d like to get access to some functions, variables of the module or the entire class you need to use module.exports property. You can assign a new value or a function to this property. For example, in class square.js you can have these exports:
exports.perimeter = (width) => width * 4;
And later on this can be used in the geometry module like so:
const square = require('./square.js');
console.log(`The perimeter of square with the edge of 8 ${square.perimeter(8)}`);
In this example, we exported the function of the module square located in square.js. This function allows calculating the perimeter of the square based on the passed length of edge parameter. We required this module in our geometry module and used its function from inside of geometry module.
The semantics of Node.js's require() function were designed to be general enough to support a number of reasonable directory structures. To get the exact filename that will be loaded when require() is called, use the require.resolve() function.
Modules are cached after the first time they are loaded. It means that by default code of every module will be executed just once. To have a module execute code multiple times, export a function, and call that function instead similar to our square perimeter example above. Modules are cached in require.cache object when they are required. By deleting a key value from this object, the next require will reload the module.
Node.js Event Emitters
One of the most powerful features that are coming with Node.js is the Event Emitter. The Event Emitter is a design pattern that allows developers to create listeners for to dispatched custom events. Similarly to well-known jQuery “on” function. Node.js has its own “on” function to allow to listen to a new event.
In order to start working with Node.js events, you need to require a Node.js events module.
var events = require(‘events’);
Node.js core API is built around asynchronous event-driven architecture in which objects that are called "emitters" emit/dispatched events that have designated names and this, in turn, causes function objects "listeners" attached to this event name to be called. All emitters should be members of EventEmitter class. To create new emitter one needs to call an EventEmitter constructor like so:
var emitter = new events.EventEmitter();
Evidently, EventEmitter class is exported through the events core Node module and we are calling its constructor to create a new emitter object. The emitter object itself has an exposed “on” function that we can use to attach a custom event. When emitter dispatches the event, all functions attached to that specific event are called synchronously. We can attach our custom event using “on” function like this:
var message = “This is my first alert”;
var status = “status”;
emitter.on(‘customAlert’, function(message, status) {
console.log(`${message} - ${status}`);
}
In this example, we created a custom event “customAlert” and attached it to the emitter with the “on” function. This function takes two parameters: the name of the custom event and callback function. In our example, the callback function is an anonymous function that calls console.log.
But it’s not enough to just declare the event. At some point, the emitter needs to dispatch it so the callbacks attached to it would be called. We can dispatch the event with the function called emit() that is also exposed through the emitter object like so:
emitter.emit(‘customAlert’, message, status);
Emit function takes a parameter of event name that needs to be emitted. Second and third arguments depend on the particular event declaration. Those arguments would be passed to the event callback function. In our example above customAlert callback expected 2 arguments: message and status.
If you would like to call the listener only once during the code execution then similarly to jQuery.once you could use emitter.once() function instead of “on” function.
Summary
In today’s part two of the blog we built upon core concepts discussed in part 1 of this series, and looked deeper into custom modules for Node.js, export functionality, and custom events.
I hope this foundational knowledge opens doors for your first asynchronous application built on Node.js.