Async Loops In Node

I've been using Node for the past few weeks and I discovered a couple neat tricks about JavaScript that I never knew before.

Anonymous functions in JavaScript can have names.

Naming an anonymous function? Seems silly at first...

//no name provided
repo.load_post(post_id,
  function(post) {
    // do something ...  
  });

//with a name
repo.load_post(post_id, 
  function with_post(post) {
    // do something ...
  });

However, as it turns out, there are benefits to naming anonymous functions, especially when it comes to pinpointing an exception within a stack trace.

But this blog post is about writing async loops in Node -- So, how does naming functions help?

Function 'Names' Are Instances

I wrote an example a while back where I used the call and apply methods to pass additional loop information. You'd be able to reference this to gather additional information about the loop you were currently in.

Except, in Node, this seems to quickly lose a meaningful scope and you're forced to assign it to a variable that you can access from other nested closures.

However, since the function object itself is accessable by name, you can use it to maintain a meaningful scope for your work.

function each(collection, action, finished) {

  //add loop information to the action
  action.index = -1;
  action.collection = collection;
  action.finished = finished || function() { };

  //assign the loop control to the 
  //anonymous method that was passed in
  action.next = function() {

    //quit now if the end has been reached
    if (++action.index >= collection.length)
      return action.finished();

    //process this item
    var value = collection[action.index];
    action(value);

  };

  //start the loop
  action.next();
}

Now, at this point, we can control the loop using the anonymous function we passed in by referring to it by name.

//saves each person
each(
  ['Hugo', 'Mary', 'Gwyn', 'Cassie', 'Ruby'], 
  function loop(person) {

    //do an async method
    settings.save_profile(
      person,

      //then on the callback...
      function when_saved() {
        console.log(item + ' was saved...');

        //... we can still access the loop
        loop.next();
      });
  });

This makes it easy to keep track of the scope of an anonymous function without needing to clutter up your code with extra variables. Now you can extend the functionality of anonymous functions with as much or as little information as you need and then access it by name. Very nice!

It is worth noting that I've heard that browser support for naming anonymous functions is rather limited in the browser world, so for the time being, it is probably best to keep this within your Node apps.

February 8, 2012

Async Loops In Node

Naming anonymous functions to make async loops easier to manage.