Justin Elkow
Justin Elkow

Reputation: 2943

Node js async.series not working with Express app --- response happening too soon

I have a Node js Express app where I am setting cookies from many different places (the server, Twitter, another database, etc). These all need to happen in series. To avoid a callback nightmare, I am trying to use Async.js. But, the response keeps getting sent BEFORE the async.series call finishes. How can I make sure the async.series completes and THEN the res.redirect is called?

CALL TO MODULE WITH ASYNC

// OTHER CODE
accountCookies(req, res, next);  // THE MODULE WITH ASYNC
res.redirect(302, 'https://' + req.host + '/account');

ASYNC MODULE

module.exports = function (req, res, next) {

req.appVariables.error = null;

// Required modules
var async = require(__dirname + '/utilities-----async.js'); // Utility for controlling node's asynchronous behavior
var userSessionObject = {};
// ...OTHER MODULES

// Cookie values set by the server
var cookieValuesSetByTheServer = function(req, res, next, userSessionObject, callback) {
    userSessionObject.STUFF = STUFF;
    logs.dev('cookieValuesSetByTheServer');
    setTimeout(function(){callback(req.appVariables.error, '1');}, 3000);
};

// Cookie values from Twitter
var cookieValuesFromTwitter = function(req, res, next, userSessionObject, callback) {
    userSessionObject.moreSTUFF = moreSTUFF;
    logs.dev('cookieValuesFromTwitter')
    callback(req.appVariables.error, '2');
};

// Cookie values from User Database
var cookieValuesFromUserDatabase = function(req, res, next, userSessionObject, callback) {
    userSessionObject.otherSTUFF = otherSTUFF;
    logs.dev('cookieValuesFromUserDatabase');
    setTimeout(function(){callback(req.appVariables.temporarilyUnavailableCalled, '3');}, 6000);
};

// Call all functions in Series
async.series([
    function(callback){
        cookieValuesSetByTheServer(req, res, next, userSessionObject, callback);
    },
    function(callback){
        cookieValuesFromTwitter(req, res, next, userSessionObject, callback);
    },
    function(callback){
        cookieValuesFromUserDatabase(req, res, next, userSessionObject, callback);
    }
], function(err, results){
    if ( err == null ) {
        logs.dev(results);
        return true;
    }
    else {
        logs.dev(err);
        return false;
    }
});

};

Upvotes: 1

Views: 939

Answers (2)

robertklep
robertklep

Reputation: 203494

You need to wait for async.series is done before you can send the response. The usual method of doing so is to pass a callback function:

accountCookies(req, res, next, function theCallbackFunction(success) {
  res.redirect(302, 'https://' + req.host + '/account');
});

// in your async module
module.exports = function (req, res, next, theCallbackFunction) {
  ...
  async.series([ ... ], function(err, results) {
    if ( err == null ) {
      logs.dev(results);
      theCallbackFunction(true);
    } else {
      logs.dev(err);
      theCallbackFunction(false);
    }
  });
};

In other words: you can't use return in async functions to pass a return value back to the caller.

Upvotes: 2

Michael Tang
Michael Tang

Reputation: 4916

You could try replacing the next callback with a middleware function that just does the res.redirect and then passes the request on.

accountCookies(req, res, function(req, res, next) {
    res.redirect(302, 'https://' + req.host + '/account');
    next();
});

Upvotes: 0

Related Questions