tree-traversal.js
function traverseDepthFirst(rootNode, options) {
  options = extend({
    subnodesAccessor: function(node) { return node.subnodes; },
    userdataAccessor: function(node, userdata) { return userdata; },
    onNode: function(node, callback, userdata) { callback(); },
    onComplete: function(rootNode) {},
    userdata: null
  }, options);

  var stack = [];
  stack.push([rootNode, options.userdata]);

  (function next() {
    if (stack.length == 0) {
      options.onComplete(rootNode);
      return;
    }

    var top = stack.pop();
    var node = top[0];
    var data = top[1];

    options.onNode(node, function() {
      var subnodeData = options.userdataAccessor(node, data);
      var subnodes = options.subnodesAccessor(node);
      async.eachSeries(subnodes,
        function(subnode, nextNode) {
          stack.push([subnode, subnodeData]);
          async.setImmediate(nextNode);
        },
        function() {
          async.setImmediate(next);
        }
      );
    }, data);
  })();
}
function traverseDepthFirst(rootNode, options) {
  options = extend({
    subnodesAccessor: function(node) { return node.subnodes; },
    userdataAccessor: function(node, userdata) { return userdata; },
    onNode: function(node, callback, userdata) { callback(); },
    onComplete: function(rootNode) {},
    userdata: null
  }, options);

  var stack = [];
  stack.push([rootNode, options.userdata]);

  (function next() {
    if (stack.length == 0) {
      options.onComplete(rootNode);
      return;
    }

    var top = stack.pop();
    var node = top[0];
    var data = top[1];

    options.onNode(node, function() {
      var subnodeData = options.userdataAccessor(node, data);
      var subnodes = options.subnodesAccessor(node);
      async.eachSeries(subnodes,
        function(subnode, nextNode) {
          stack.push([subnode, subnodeData]);
          async.setImmediate(nextNode);
        },
        function() {
          async.setImmediate(next);
        }
      );
    }, data);
  })();
}
function traverseDepthFirst ( rootNode , options ) { options = extend ( { subnodesAccessor : function ( node ) { return node . subnodes ; } , userdataAccessor : function ( node , userdata ) { return userdata ; } , onNode : function ( node , callback , userdata ) { callback ( ) ; } , onComplete : function ( rootNode ) { } , userdata : null } , options ) ; var stack = [ ] ; stack . push ( [ rootNode , options . userdata ] ) ; ( function next ( ) { if ( stack . length == 0 ) { options . onComplete ( rootNode ) ; return ; } var top = stack . pop ( ) ; var node = top [ 0 ] ; var data = top [ 1 ] ; options . onNode ( node , function ( ) { var subnodeData = options . userdataAccessor ( node , data ) ; var subnodes = options . subnodesAccessor ( node ) ; async . eachSeries ( subnodes , function ( subnode , nextNode ) { stack . push ( [ subnode , subnodeData ] ) ; async . setImmediate ( nextNode ) ; } , function ( ) { async . setImmediate ( next ) ; } ) ; } , data ) ; } ) ( ) ; }
Asynchronously traverses the tree depth first.
Asynchronously traverses the tree depth first .