Asynchronous Calls and Recursion with Node.js

In your example you have no recursive calls. If I understand correctly you want to say that recurse(point, otherFunc); is the beginning of a recursive call.

Then just go back to the definition of the recursive call (which you have not shown in your post) and do this (add a third argument for a callback function to be called in the end of recursion; the caller will pass it as a parameter):

function recurse(startingPlace, otherFunc, callback_one) {
    // code you may have ...
    if (your_terminating_criterion === true) {
         return callback_one(val); // where val is potentially some value you want to return (or a json object with results)
    }
    // more code you may have
}

Then in the original code that you posted, make this call instead (in the inner-most part):

recurse(startingPlace, otherFunc, function (results) {
    // results is now a variable with the data returned at the end of recursion
    console.log ("Recursion finished with results " + results);
    callback();   // the callback that you wanted to call right from the beginning
});

Just spend some time and try to understand my explanation. When you understand, then you will know node. This is the node philosophy in one post. I hope it is clear. Your very first example should look like this:

var start = function(callback) {
  request.get({
    url: 'aaa.com'
  }, function (error, response, body) {
    var startingPlace = JSON.parse(body).id;
    recurse(startingPlace, otherFunc, function (results) {
        console.log ("Recursion finished with results " + results);
        callback();
    });
  });
};

Below is only additional information in case you are interested. Otherwise you are set with the above.

Typically in node.js though, people return an error value as well, so that the caller knows if the function that was called has finished successfully. There is no big mystery here. Instead of returning just results people make a call of the form

return callback_one(null, val);

Then in the other function you can have:

recurse(startingPlace, otherFunc, function (recError, results) {
    if (recErr) {
         // treat the error from recursion
         return callback(); // important: use return, otherwise you will keep on executing whatever is there after the if part when the callback ends ;)
    }

    // No problems/errors
    console.log ("Recursion finished with results " + results);
    callback();   // writing down `return callback();` is not a bad habit when you want to stop execution there and actually call the callback()
});

Update with my suggestion

This is my suggestion for the recursive function, but before that, it looks like you need to define your own get:

function myGet (a, callback) {
    request.get(a, function (error, response, body) {
        var nextPlace = JSON.parse(body).place;
        return callback(null, nextPlace); // null for no errors, and return the nextPlace to async
    });
}

var recurse = function(startingPlace, callback2) {
    request.get({
        url: 'bbb'
    }, function(error1, response1, body1) {
        // store body somewhere outside these funtions
        // make second request
        request.get({
            url: 'ccc'
        }, function(error2, response2, body2) {
            var anArray = JSON.parse(body2).stuff;
            if (anArray) {
                // The function that you want to call for each element of the array is `get`.
                // So, prepare these calls, but you also need to pass different arguments
                // and this is where `bind` comes into the picture and the link that I gave earlier.
                var theParallelCalls = [];
                for (var i = 0; i < anArray.length; i++) {
                    theParallelCalls.push(myGet.bind(null, {url: 'ddd'})); // Here, during the execution, parallel will pass its own callback as third argument of `myGet`; this is why we have callback and callback2 in the code
                }
                // Now perform the parallel calls:
                async.parallel(theParallelCalls, function (error3, results) {
                    // All the parallel calls have returned
                    for (var i = 0; i < results.length; i++) {
                        var nextPlace = results[i];
                        recurse(nextPlace, callback2);
                    }
                });
            } else {
                return callback2(null);
            }
        });
    });
};

Note that I assume that the get request for 'bbb' is always followed by a get request for 'ccc'. In other words, you have not hidden a return point for the recursive calls where you have the comments.


Typically when you write a recursive function it will do something and then either call itself or return.

You need to define callback in the scope of the recursive function (i.e. recurse instead of start), and you need to call it at the point where you would normally return.

So, a hypothetical example would look something like:

get_all_pages(callback, page) {
    page = page || 1;
    request.get({
        url: "http://example.com/getPage.php",
        data: { page_number: 1 },
        success: function (data) {
           if (data.is_last_page) {
               // We are at the end so we call the callback
               callback(page);
           } else {
               // We are not at the end so we recurse
               get_all_pages(callback, page + 1);
           }
        }
    }
}

function show_page_count(data) {
    alert(data);
}

get_all_pages(show_page_count);