Search This Blog

2017/10/09

Node.js:Event Emitter

Many objects in a Node emit events for example, a net.Server emits an event each time a peer connects to it, an fs.readStream emits an event when the file is opened. All objects which emit events are the instances of events.EventEmitter.                
     
The event emitter allows us to decouple the producers and consumers of events using a standard interface.

EventEmitter class lies in the events module. EventEmitter provides multiple properties like on and emiton property is used to bind a function with the event and emit is used to fire an event.

var http = require("http");
var events = require('events');
var eventEmitter = new events.EventEmitter();

var serviceDownAlert = function(){
  console.log('The Ping Client --> xxx.xxx.xxx.xxx is not responding..');
}

//attach listener
eventEmitter.on('serviceDown', serviceDownAlert);

function pingClient(){
  var _host="35.185.129.118",
  _path="/isalive.html",_port="5432";
 
  httpGet(_host,_port,_path,function (err,res){
    console.log("Pinging..");
    console.log(res);
    if(res.statusCode.toString() != "200"){
      eventEmitter.emit('serviceDown');
    }
  });
}

function httpGet(host,port,path,callback){
  var options = {
    "method": "GET",
    "hostname": host,
    "port": port,
    "path": path,
    "headers": {
      "cache-control": "no-cache"
    }
  };
    var req = http.request(options, function (res) {
    var chunks = [];
    var result =
    res.on("data", function (chunk) {
      chunks.push(chunk);
    });
   
    res.on("end", function () {
      var body = Buffer.concat(chunks);
      result = {"response":body.toString(),"statusCode":res.statusCode};
      callback(null,result);
    });

    res.on('error', function (err) {
      result = {"response":null,"statusCode":res.statusCode};
      callback(err, result);
    });
  }).on('error', function(err) {
    result = {"response":null,"statusCode":"-1"};
    callback(err, result);
});
req.end();
}
//start ping client
pingClient();

Here a Ping-Client hits a server URL and expects HTTP 200 status code in response, if it doesn’t receives 200 http status code it emits “serviceDown” event.
serviceDownAlert” function is registered as event listener, after “serviceDown” event is emitted listeners get called.

We can attach multiple event listener functions to a single event even a anonymous function can also be attached as listener function to an event.
Anonymous function as Event Listener:

eventEmitter.on('serviceDown', function()
{
    console.log('Anonymous Fuction as Event Listener:: The Ping Client --> xxx.xxx.xxx.xxx is not responding..');
}

Methods of EventEmitter class:
1.       emitter.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.

2.       emitter.on(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. It can also be called as an alias of emitter.addListener()

3.       emitter.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.

4.       emitter.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.

5.       emitter.removeAllListeners([event]):Removes all listeners, or those of the specified event.

6.       emitter.setMaxListeners(n):By default EventEmitters will print a warning if more than 10 listeners are added for a particular event.

7.       emitter.getMaxListeners():Returns the current maximum listener value for the emitter which is either set by emitter.setMaxListeners(n) or defaults to EventEmitter.defaultMaxListeners.

8.       emitter.listeners(event):Returns a copy of the array of listeners for the specified event.

9.       emitter.emit(event[, arg1][, arg2][, ...]):Raise the specified events with the supplied arguments.

10.    emitter.listenerCount(type): Returns the number of listeners listening to the type of event.

References        


2017/10/08

Event Loop overview

The Event Loop is a programming construct that waits for & dispatches events  in a program.
Event is usually defined as significant change in state of an object.

Node.js is a JavaScript runtime built on Chrome's V8 JavaScript engine. Node.js uses an event-driven, non-blocking I/O model.

Event Loop lies at the heart of Node.js that is responsible for making it event driven (asynchronous).

Event Loop overview:

In most of the modern operating systems, system kernels are multi-threaded, they are capable of handling multiple operations executing in the background.Node.js tries to capitalize on OS infrastructure.
Whenever a task arrives for execution with node.js it gets queued, task gets pulled for execution from this queue sequentially. Event loop checks if current task requires any Blocking IO Operations or may demands more time for complex computation tasks embedded in it.
 If it does not require blocking IO or complex computation then Event Loop will process all steps demanded in that task & serve response.
If task requires very complex computation or Blocking IO, Even Loop does not process it, but offloads the operations to the system kernel directly using asynchronous interfaces provided by operating system or by using internal thread pool that communicate with OS which are not providing such asynchronous API also add this offloaded task for listening for update of status (such change of state usually referred as an event) via event listeners.
 Rather than idle waiting for offloaded task to complete it moves on to new task in queue. Meanwhile when offloaded task finishes and Event Loop comes to know about it through listeners, now EventLoop starts executing this task from where it left after finishing tasks in hand it.
To understand EventLoop in more details let’s look at event loop phases.

Phases of Event Loop:                                                                                                                Event loop goes through its phases in cyclic manner. Each phase has own FIFO callback queue also called Event queue. Callbacks are event in themselves. When the event loop enters a given phase, it performs any operations specific to that phase, then execute callbacks in that phase's queue until the queue has been exhausted or the maximum number of callbacks has executed.

Event loop has following phases

             1)     timers: this phase executes callbacks scheduled by setTimeout() and setInterval().
2)     I/O callbacks: executes almost all callbacks with the exception of close callbacks, the ones scheduled by timers, and setImmediate().
3)     idle, prepare: only used internally.
4)     poll: retrieve new I/O events; node will block here when appropriate.
5)     checksetImmediate() callbacks are invoked here.
6)     close callbacks: e.g. socket.on(‘close’ ...).

Suppose EventLoop is inside poll phase & at the same time system kernel adds more callbacks into poll callback queue then poll phase has to run much longer than a timer's threshold

Event Loop Phases details:

I/O callbacks Phase: I/O callbacks executes callbacks for some system operations such as types of TCP errors e.g. ECONNREFUSED for *nix systems which requires wait to report the error.
Poll Phase: Poll phase Executes scripts for timers whose threshold has elapsed, then Processes events in the poll queue.
If there are no timers scheduled and poll queue is not empty event loop will iterate through its queue of callbacks executing them synchronously until either the queue has been exhausted, or the system-dependent hard limit is reached.
For empty poll queue If scripts have been scheduled by setImmediate(), the event loop will end the poll phase and continue to the check phase to execute those scheduled scripts rather than waiting.
 But If scripts have not been scheduled by setImmediate(), the event loop will wait for callbacks to be added to the queue, then execute them immediately.
Check phase: This phase allows a person to execute callbacks immediately after the poll phase has completed. Runs all callbacks registered via setImmediate().
close callbacks phase: If a socket or handle is closed abruptly (e.g. socket.destroy ()), the 'close' event will be emitted in this phase. Otherwise it will be emitted via process.nextTick().


Event loop's order of operations:



Event Loop is a single threaded and semi-infinite loop. The reason why this is called a semi-infinite loop is because this actually quits at some point when there is no more work to be done.
What is process.nextTick ()?

In Node.js, each iteration of an Event Loop is called a tick. process.nextTick() get processed after the current operation completes regardless of the current phase of the event loop.

Suppose if the event loop is in Timer phase and there were 5 callbacks in the timer queue already; and event loop is busy executing the third one. By that time if few process.nextTick() callbacks are pushed to nextTickQueue, the event loop will execute all of them synchronously after completing the current callback execution (which is 3rd one) and will resume the Timer callback execution again from the 4th callback.

Consider following code snippet

function callback(){
    console.log('wrapped inside nexttick');
  }
  process.nextTick(callback);
  console.log('task1');
  console.log('task2');


Output of this snippet is as follows

C:\Users\Sangram\Desktop>node test.js
task1
task2
wrapped inside nexttick
console.log associated with function callback() get called after task of printing task1 & task2 as task of printing task1 & task2.  

process.nextTick() is technically not a part of the event loop.

What is Libuv?

Node.js consumes the low-level non-blocking, asynchronous hardware I/O functionalities provided by Operating System implementations. epoll in Linux, kqueue in BSD systems (MacOS), event ports in Solaris, IOCP (Input Output Completion Port) in Windows. Not all the types of I/O can be performed using these implementations. Even on the same OS platform, there are complexities in supporting different types of I/O. Certain systems, such as Linux does not support complete asynchrony for file system access. And there are limitations in file system event notifications/signaling with kqueue in MacOS systems.

    NodeJS DNS functions such as dns.lookupaccesses system configuration files such as nsswitch.conf,resolv.conf and /etc/hosts , file system complexities described above are also applicable to dns.resolve function.

Therefore, a thread pool has been introduced to support I/O functions which cannot be directly addressed by hardware asynchronous I/O utils such as epoll/kqueue/event ports or IOCP. Now we know that not all the I/O functions happen in the thread pool.Some I/O get performed using native hardware implementations while preserving complete asynchrony, and there are certain I/O types which should be performed in the thread pool so that the asynchronous nature can be guaranteed.
To govern this entire process while supporting cross-platform I/O, there should be an abstraction layer which encapsulates these inter-platform and intra-platform complexities and expose a generalized API for the upper layers of Node. Libuv is that abstraction layer.
libuv is cross-platform support library which was originally written for NodeJS. It’s designed around the event-driven asynchronous I/O model.

The library provides much more than a simple abstraction over different I/O polling mechanisms: ‘handles’ and ‘streams’ provide a high level abstraction for sockets and other entities; cross-platform file I/O and threading functionality is also provided, amongst other things.

Below diagram summarizes libuv stack w.r.t. Operating system IO library .


.
Reference            

2017/10/07

Node.js introduction

What is Node.js?

Node.js is a JavaScript runtime built on Chrome's V8 JavaScript engine.
   We can draw analogy between JavaScript runtime & Java Virtual Machine. A ‘virtual machine’ refers to the software-driven emulation of a given computer system. There are many types of virtual machines, and they are classified by how precisely they are able to emulate or substitute for actual physical machines.
A ‘system virtual machine’, for example, provides a complete emulation of a platform on which an operating system can be executed.e.g. Virtual Box & Parallels
A ‘process virtual machine’, on the other hand, is less fully-functional and can run one program or process. Wine is a process virtual machine that allows you to run Windows applications on a Linux machine, but does not provide an entire Windows OS on a Linux box.
There are other JavaScript runtime than V8 too. Notably few are Microsoft’s Chakra & Spider Monkey. But Node.js which an open source project stick to V8.
Node.js uses an event-driven, non-blocking I/O model that makes it lightweight and efficient. Node.js' package ecosystem, npm, is the largest ecosystem of open source libraries in the world.
An event can be defined as "a significant change in state.

What is callback function?

A reference to executable code, or a piece of executable code, that is passed as an argument to other code.
  Let’s explore real life example. You go to Pizza Store order quite few pizzas & Cokes, now the pizza can’t be made at speed of thought so the counter guy will ask you about your contact number. No need for you to wait at counter & you can happily do something else. Once pizza got ready pizza counter guy will ring you that’s kind of callback.
function PizzaMaker(orderandContactDetailscallback) {
    console.log("time consuming task of making pizza based on order, blocked execution till  It finish");

    //ring the guy ,hey your pizza is ready
    callback();
}



Calling PizzaMaker the  function with callback as follows
var  _orderandContactDetails = {"type":"onion paneer","contact":"34535456436","extraCheese":"yes","takeAwayOrder":"yes"};
PizzaMaker(orderandContactDetails ,function(error,result){
   if(error){
     console.log("take a refund & go to other restaurant");
  }
  else{
     console.log("take a home yummy pizza");
    }
});


Here PizzaMaker is host function & below anonymous function is callback function which we are passing to host function.

function(error,result){
    if(error){
      console.log(“take a refund & go to other restaurant”);
   }else{
      console.log(“take a home yummy pizza”);
   }
}


Convention:
  Often last parameter of host function is used for callback function while callback function’s first parameter is used for passing error & second parameter used to pass result. It entirely depends upon host function implementation. It is not binding to keep callback function bi parametered or maintain order of parameter.
W.r.t. our example, Event of finished making pizza order is trigger to callback. Callback is one of the most basic approaches in event driven model. Many native functions in node.js core library do implement callback. Though there is other approach like promise too.



Asynchronous Nature of Node.js:
Consider below example
const fs = require('fs');

console.log('Before loop');
fs.readFile('./sample.txt', (err, data) => {
  if (err) throw err;
  else {
     console.log("File Content");
     console.log(data.toString());
  }
});
console.log('After loop');

Output:
C:\Users\Sangram\projects\tut_async>node index.js
Before loop
After loop
File Content
ONE
TWO
THREE

Here sequence of execution is not followed in traditional programming model text after loop would have been last.
C:\Users\Sangram\projects\tut_async>node index.js
Before loop
File Content
ONE
TWO
THREE
After loop

Here we are reading sample.txt file which is basically an IO operation.IO operation can take long time to finish based on task it executing. If next lines in sequence wait till completion of IO operation then it becoming blocking but here IO operation do not block execution of next line. Similarly HTTP Requests, Database requests are also implemented in non-blocking way in node.js.Non-blocking nature gives node.js edge over other and make it more efficient.
Node.js provide minimal feature out of box for implementing additional features one need to install concern package. Due to this approach node.js has lesser memory footprint. Which makes node.js lightweight?
For Loop & While loop
An execution of for loop & while loop is synchronous that means until execution of loop block finishes no line below will be executed. See below example
console.log('Before loop');
console.log("For loop");
for(var i=0;i < 5;i++){
    console.log(i);
}
console.log("While loop");
var j=0
while(j < 5){
    console.log(j);
    j++;
}
console.log('After loop');

Output
C:\Users\Sangram\projects\tut_async>node index.js
Before loop
For loop
0
1
2
3
4
While loop
0
1
2
3
4
After loop

Here loop block executed in sequential order.
Word of caution while mixing Blocking and Non-Blocking Code:
Consider below code.
const fs = require('fs');
fs.readFile('./sample.txt', (err, data) => {
  if (err) throw err;
  else{
    console.log("File Content");
    console.log(data.toString());
  }
});
fs.unlinkSync('./sample.txt');
    
Here readFile function is executing in non-blocking mode so, before reading sample.txt finishes the unlinkSync function get called which is deleting the very file we are trying to read.
You can correct simply by calling unlinkSync inside callback of readFile function.
const fs = require('fs');
fs.readFile('./sample.txt', (err, data) => {
  if (err) throw err;
  else{
    console.log("File Content");
    console.log(data.toString());
    fs.unlinkSync('./sample.txt');
  }
});

References