Avoiding callback hell in nodeJs / Passing variables to inner functions

Here's an example of something I'd like to simplify:

exports.generateUrl = function (req, res) {
    var id = req.query.someParameter;

    var query = MyMongooseModel.findOne({'id': id});
    query.exec(function (err, mongooseModel) {
        if(err) {
            //deal with it
        }

        if (!mongooseModel) {
            generateUrl(Id,
                function (err, text, url) {
                    if (err) {
                        res.status(HttpStatus.INTERNAL_SERVER_ERROR).send(err);
                        return;
                    }
                    var newMongooseModel = new AnotherMongooseModel();
                    newMongooseModel.id = id;

                    newMongooseModel.save(function (err) {
                        if (err) {
                            res.status(HttpStatus.INTERNAL_SERVER_ERROR).send(err);
                        } else {
                            res.send({url: url, text: text});
                        }
                    });
                });
        } else {
            //deal with already exists
        }
    });
};

I've seen other SO answer where they tell you to use named functions, but don't say how to deal with variable you want to pass in or use jQuery's queue. I do not have the luxury of either.

I understand that I can replace my anonymous functions with names functions, but then I would need to pass arounds variables. How would my inner function access res for instance if the function is defined elsewhere?

The core to your question is:

I understand that I can replace my anonymous functions with names functions, but then I would need to pass arounds variables. How would my inner function access res for instance if the function is defined elsewhere?

The answer is to use a function factory.

In general, this:

function x (a) {
    do_something(function(){
        process(a);
    });
}

can be converted to this:

function x (a) {
    do_something(y_maker(a)); // notice we're calling y_maker,
                              // not passing it in as callback
}

function y_maker (b) {
    return function () {
        process(b);
    };
}

In the code above, y_maker is a function that generates a function (let's call that function's purpose "y"). In my own code, I use the naming convention .._maker or generate_.. to denote that I'm calling a function factory. But that's just me and the convention is in no way standard or widely adopted in the wild.

So for your code you can refactor it to:

exports.generateUrl = function (req, res) {
    var id = req.query.someParameter;

    var query = MyMongooseModel.findOne({'id': id});
    query.exec(make_queryHandler(req,res));
};

function make_queryHandler (req, res) {
    return function (err, mongooseModel) {
        if(err) {
            //deal with it
        }
        else if (!mongooseModel) {
            generateUrl(Id,make_urlGeneratorHandler(req,res));
        } else {
            //deal with already exists
        }
}}

function make_urlGeneratorHandler (req, res) {
    return function (err, text, url) {
        if (err) {
            res.status(HttpStatus.INTERNAL_SERVER_ERROR).send(err);
            return;
        }
        var newMongooseModel = new AnotherMongooseModel();
        newMongooseModel.id = id;
        newMongooseModel.save(make_modelSaveHandler(req,res));
}}

function make_modelSaveHandler (req, res) {
    return function (err) {
        if (err) res.status(HttpStatus.INTERNAL_SERVER_ERROR).send(err);
        else res.send({url: url, text: text});
}}

This flattens out the nested callbacks. As an additional benefit, you get to properly name what the function is supposed to do. Which I consider good practice.

It also has the added advantage that it is significantly faster than when using anonymous callback (either with nesting callbacks or with promises, though if you pass named functions to promise.then() instead of anonymous functions then you'll get the same speed up benefits). A previous SO question (my google-fu is failing me today) found that named functions are more than twice the speed (if I remember correctly it was more than 5 times faster) of anonymous functions in node.js.

Use promises. Using Q and mongoose-q it would give: something like that:

exports.generateUrl = function (req, res) {
    var id = req.query.someParameter;
    var text = "";

    var query = MyMongooseModel.findOne({'id': id});
    query.execQ().then(function (mongooseModel) {

        if (!mongooseModel) {
            return generateUrl(Id)

     }).then(function (text) {
       var newMongooseModel = new AnotherMongooseModel();
       newMongooseModel.id = id;
       text = text;

       newMongooseModel.saveQ()
     }).then(function (url) {
        res.send({url: url, text: text});
     }).fail(function(err) {
        res.status(HttpStatus.INTERNAL_SERVER_ERROR).send(err);
     });
};

Named functions will be executed within the same scope that the anonymous functions are and would have access to all of variables you are currently using. This approach would make your code less nested and more readable (which is good) but would still technically be in "callback hell". The best way to avoid situations like this is to wrap your asynchronous libraries (assuming they don't already provide promises) with a promise library like Q. IMO, promises provide a much more clear picture of the execution path.

You can avoid the predicament of not knowing where variables came from by binding parameters to your named function using bind, for instance:

function handleRequest(res, err, text, url) {
    if (err) {
        res.status(HttpStatus.INTERNAL_SERVER_ERROR).send(err);
        return;
    }
    var newMongooseModel = new AnotherMongooseModel();
    newMongooseModel.id = id;

    newMongooseModel.save(function (err) {
        if (err) {
            res.status(HttpStatus.INTERNAL_SERVER_ERROR).send(err);
        } else {
            res.send({url: url, text: text});
        }
    });
}

...
generateUrl(Id, handleRequest.bind(null, res));