This is an interesting topic due to the asynchronous nature of javascript.

Basics

  • Recursion would be easy in most languages. E.g. to solve the problem of permutation in C, one solution is:
      void swap(int* a, int u, int v) {
        int t = a[u];
        a[u] = a[v];
        a[v] = t;
      }
    
      int perm(int* a, int n, int s) {
        int i;
        if(s == n) {
          for(i=0;i<n;i++) {printf("%d ", a[i]);}
          printf("\n");
          return;
        }
        for(i=s;i<n;i++) {
          swap(a,i,s);
          perm(a,n,s+1);
          swap(a,i,s); 
        }
      }
    
    This would be similar in Javascript:
      function swap(a, u, v) {
        var t = a[u];
        a[u] = a[v];
        a[v] = t;
      }
    
      function perm(a, u, v) {
        var i;
        if(s == n) {
          for(i=0;i<n;i++) {console.log(a[i]);}
          return;
        }
        for(i=s;i<n;i++) {
          swap(a,i,s);
          perm(a,n,s+1);
          swap(a,i,s); 
        }
      }
    
    Click to run above code in browser:

    Recursion + Callbacks

    Recursion would be complex in Javascript however, if asycnchronous I/O is involved. E.g. to generate breadcrumb navigation in your app, you need find an item's parent node in the database, and parent's parent node, and so on. until you reach root:
    function findParent(path, db, child, rs, cb) {
      db.find({children:{$elemMatch:{id:child}}}).toArray(function (err, items) {
        if(items.length==0) {
          rs.push(path.slice(0));
          cb();
        } else {
          _(items).each(function(e) {
            path.push(e.id);
            findParent(path, db, e.id, rs, function(rs1){
              rs = rs.concat(rs1);
              path.pop();
            });
          });
        }
      });
    }
    
    This most likely won't work. Javascript's inherent async nature means function returns immediately. Stack doesn't change as expected in other languages (i.e. functions calls are not pushed to the stack), and callback-based control flow makes it unpredictable to write in linear logistics. Fortuantely there are a few control flow libs for Javascript such as async, which easily solves this problem:
    function findParent(path, db, child, cb) {
      db.find({children:{$elemMatch:{id:child}}}).toArray(function (err, items) {
        var rs = [];
        if( items.length==0 ) {
          cb('no parent', path.slice(0));
        } else {
          async.eachSeries(items, function(e, cb1) {
            path.push(e.id);
            findParent(path, db, e.id, function(rs1){
              rs = rs.concat(rs1);
              path.pop();
              cb1();
            });
          }, function(err){
            if(err) console.log('async error.');
            cb(err, rs);
          });  
        }
      });
    }
    
    By trigging the callback only after finishing all sub function calls makes sure the code executes in FILO order (which is a stack's behavior).