Monday, August 26, 2013

Node.js fs.watchFile error EventEmitter memory leak detected . Max listeners

This happens when fs.WatchFile is called on the same file multiple times.
Explaination
fs module contains a local object "statWatchers" {} to track files being watched.
So when fs.watchFile('fileX') is called a new statWatcher object is created if one does not exits and stored it in the "statWatchers" object against the file name. If there is already a statWatcher object associated with this file, it is returned.
statWatcher["fileX"] = new statWatcher();
And then calls addListener('change', listener) on the statWatcher object associated with this file.
Incase fs.watchFile is called for 11 times on "fileX", it will result in calling addListener on the statWatcher for event "change" 11 times.
EventEmitter throws an error if tried to add more than 11 listeners for the same event.

object.__proto__ and the prototype , Javascript

Everything in javascript is object.
And every object, it may be a function/ {} / new Object() , in javascript has an internal property called [[proto]].

[[proto]] is the very reason for prototype inheritance in javascript.

This internal property is exposed to the programmer through proto. This is a non standard.
Not all JS environments support this.

How does an object we create using constructor functions gets its [[proto]]?

Only objects whose [[class]] is "Function" gets the property 'prototype'. What it means is that every function declared when executed by the JS engine, it creates an object. Its [[class]] is set to "Function" and a property "prototype" is attached to this function object. By default this prototype is an object with one property "constructor" pointing to the function object.

When the above function is invoked as part of new operator like new constructorFn() , the JS engine creates an object , its [[class]] property set to "Object" and [[proto]] property set to the object pointed to by the [[proto]] of the constructor function.

Since this new created object is of class "Object" , it does not have the "prototype" property.
But has __proto__ pointing to the object as explained above

In nutshell, proto exists is in every object.

Prototype exists, by default, only in objects whose [[class]] is 'Function'.What this means is only functions (created via function statement , function expression , Function constructor fn) will have this property.

require in nodejs

Assuming this is the first time the module is being required.

For example ,

var x = require('file1.js');
contents of file1.js;
====================
module.exports = '123'

When the above statement is executed, a 'Module' object is created.
Module constructor function is provided below,

function Module(id, parent) {
    this.id = id;
    this.exports = {}; // the exports property which is actually return on require
    this.parent = parent;
    if (parent && parent.children) {
        parent.children.push(this);
    }

    this.filename = null;
    this.loaded = false;
    this.children = [];
}

As you see each module object has a property with name 'exports'.
This is what is eventually returned as part of require.

Next step of require is to wrap the contents of file1.js into an anonymous function like below :

(function (exports, require, module, __filename, __dirname) { 
    //contents from file1.js
    module.exports = '123;
});

And the above anonymous function is invoked the following way, module here refers to the Module Object created earlier.

(function (exports, require, module, __filename, __dirname) { 
    //contents from file1.js
    module.exports = '123;
}) (module.exports,require, module, "path_to_file1.js","directory of the file1.js");

As we can see inside the function , exports formal argument refers to module.exports.
In essence its a convenience provided to the module programmer.

However this convenience need to be exercised with care.
In any case if trying to assign a new object to exports ensure we do it this way.

exports = module.exports = {};

If we do it following way wrong way, module.exports will still be pointing to the object created as part of module instance.

exports = {};

As as result adding anything to the above exports object will have no effect to module.exports object and nothing will be exported or returned as part of require.