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); 
  
   });

No comments: