3

Trying to cleanup my callback spaghetti code using the Q promise library in my nodejs express app, but I'm having trouble translating some parts of it. Having trouble passing multiple arguments to functions and dealing with the scope.

Here's a simplified "synchronous" version to show my logic:

function updateFacebook(req, res) {
    var user = getUserFromDB(userid);
    var profile = getUserProfileFromAPI(accessToken);

    var success = updateUserDB(user, profile);
    res.json({ result: success });
}

So I convert the callback functions to return promises

function getUserFromDB(userid) {
    var deferred = Q.defer();
    // somewhere in here there's a deferred.resolve(user object);
    queryMongo()...
    return deferred.promise;
}

function getUserProfileFromAPI(accessToken) {
    var deferred = Q.defer();
    // somewhere in here there's a deferred.resolve(profile object);
    request()...
    return deferred.promise;
}

function updateUserDB(user, profile) {
    var deferred = Q.defer();
    // somewhere in here there's a deferred.resolve(updated user object);
    updateMongo()...
    return deferred.promise;
}

function handleResponse(res, user) {
    var deferred = Q.defer();

    // was thinking about putting the res.json here
    // i have no way of passing in the res
    // and res is out of scope...
    res.json({});

    return deferred.promise;
}

Now the problem is linking them up, I tried...

Q.when(getUserFromDB(userid), getUserProfileFromAPI(accessToken))
 .spread(updateUserDB)
 .done(handleResponse);

Q.all([getUserFromDB(userid), getUserProfileFromAPI(accessToken)])
 .spread(updateUserDB)
 .done(handleResponse);

Super confused. Any direction would be much appreciated.

5
  • What arguments are being passed to updateUserDb Commented Aug 25, 2014 at 19:01
  • the mongo user object and the facebook json response. Commented Aug 25, 2014 at 19:02
  • @YarGnawh this actually looks like correct usage except for res. Are you asking about how to pass res? Also +1 for clear question and synchronous exmample. Commented Aug 25, 2014 at 19:03
  • @BenjaminGruenbaum yes. since deferred.resolve() can only pass one argument, spread() is the only option. i don't see how i can fulfill handleResponse(res, user) Commented Aug 25, 2014 at 19:09
  • slightly off-topic question... would it make sense to bind the res object to the promise at the beginning? Q.bind({ res: res }).when(....) Commented Aug 25, 2014 at 19:16

1 Answer 1

3

Looks like your handleResponse is expecting two params, but updateUserDB is only resolving a single object. You could do something like:

function getResponseHandler(res) {
    return function(user) {
        // your handleResponse code here
        // which now has access to res
    }
}

and then call it like:

Q.all([getUserFromDB(userid), getUserProfileFromAPI(accessToken)])
 .spread(updateUserDB)
 .done(getResponseHandler(res));
Sign up to request clarification or add additional context in comments.

4 Comments

It might be simpler to use a closure scope here.
@NG thanks for the example. how does the user object get passed to the getResponseHandler(res) ?
@YarGnawh the getResponseHandler(res) returns a function that receives the user object from updateUserDB. That function also has access to the res object.
would returning that anonymous function "reset" the stack?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.