Sunday, March 17, 2013

Iterator for async nodejs operations


Problems in paradise... fixed !

Code from the Javascript CMS:


var nr = 0;
  for (var x in aPage.children) { 
    var cp = aPage.children[x];
    nr += 10;
    if (cp.item.sortorder != nr) {
      cp.item.sortorder = nr;
      cp.item.doUpdate(this, function() {});
      // todo: either trust in the Force or daisy chain them
    }
  }
  final();

The Force didn't work, because somewhere in "final" we closed the database connection of the current http request...

So this could have been a solution, daisy chaining:


var nr = 0, max= aPage.children.length;
  function one() {
    if (x < max) {
     var cp = aPage.children[x++];
     nr += 10;
     if (cp.item.sortorder != nr) {
        cp.item.sortorder = nr;
        cp.item.doUpdate(this, one); 
     }
    } else {
      final();
    }
  }
  one();

But one can do better no?

Why not make an iterator for this kind of stuff
Application.each = function(list, iterator, finished) {
    var nr = list.length;
    function one(current) {
     if (current >= nr) {
       finished();
     
     } else {
       iterator.call(list[current], function(err) {
         if (err) {
           finished(err);
         }
         one(current+1);
       });
     }
    }
    one(0);
  };

Daisy chain operator

  • list should be an array
  • iterator is a function that should the passed function when done

    if it passes an error to the function the loop end here
  • finished is a function that is called when everything is done with no parameter

    or that is called when the first error occurs

An example

var list = [1, 2, 3, 4, 5];
   var sum = 0;

   Application.each(list, function(done) { 
    sum += this; 
    done(); // pass an error if something went wrong

   }, function(err) { 
     if (err) 
       console.log("error: " + err);
     else
       console.log("sum = " + sum); 
  
   });

Wednesday, March 06, 2013

Tutorial - Explaining the module export system of nodejs by example


Johan Coppieters - Lector Web Development Howest - Brugge


In this short note I try to explain the usage of the 'module.exports' object when using 'require' in a nodejs script. There is also a shorthand 'exports', which is an alias to 'module.export', don't use is, it is confusing.

In your module you can add something to the object 'module.exports'. The require function in a script using your module, will return this same object (with all the things in it, that you added, variables, functions, objects, ...)


in a module -> module.exports is a reference to an object

in a script -> require("module-filename") returns this object


Exporting functions


Defining a module

src/myModule.js


module.exports.turnOn = turnOn;
module.exports.turnOn = turnOff;
module.exports.isOn = isOn;

var switchState = false;

function turnOn() { switchState = true; } 
function turnOff() { switchState = false; }
function isOn() { switchState switch; }

Using this module

src/example.js

var aBulb = require("./myModule.js");

console.log("bulb is on " + aBulb.isOn());
aBulb.turnOn();
console.log("bulb is on " + aBulb.isOn());


The better object oriented way

If you want to return a single function from a module definition (for example a contructor function), you can directly set the exports variable

src/myModule1.js


module.exports = Lighting;

function Lighting() {
  this.switch = false;
}

Lighting.prototype.turnOn = function () {
  this.switch = true;
};
Lighting.prototype.turnOff = function () {
  this.switch = false;
};
Lighting.prototype.isOn = function () {
  return this.switch;
};

Using this module / object definition

src/example.js


var Bulb = require("./myModule1.js");

var aBulb = new Bulb();
console.log("bulb is on " + aBulb.isOn());
aBulb.turnOn();
console.log("bulb is on " + aBulb.isOn());


A complete library

If you have a number of modules you want to expose, put them all into a directory (example "myMods") and add a file index.js

src/myMods/index.js


module.export.module1 = require("./myModule1.js");
module.export.module2 = require("./myModule2.js");


In myModule 1 and 2.js just do as above.


Using these modules: in example.js which sits in a directory containing the myMods directory (if not, specify a different path, for example: "../libs/myMods")


src/example.js


var myMods = require("./myMods");

var aBulb = new myMods.Bulb();
console.log("bulb is on " + aBulb.isOn());
aBulb.turnOn();
console.log("bulb is on " + aBulb.isOn());