0

I have the following code in node v6.3.0 running on an api that runs two separate promises depending on a conditional of whether a param exists in the POST request.

if (paramExists) {
    // call database with this query
    User.filter(/* do something with param */)
        .then(function (user) {
            Data.filter(/* same in both conditions */)
                .then(function (data) {
                    // join data and user
                    res.send(joinedData);
                })  // omit catch for clarity
        })  // omit catch for clarity
} else {
    // call database with this query
    User.filter(/* do something with header */)
        .then(function (user) {
            Data.filter(/* same in both conditions */)
                .then(function (data) {
                    // join data and user
                    res.send(joinedData);
                })  // omit catch for clarity
        })  // omit catch for clarity
}

I am sure there is a way to DRY up this code so that the first promise in both conditions passes the user to the second promise, but I can't figure out how. Should I use a generator, or is there a way of doing this with promises that I am not getting?

alex
  • 5,467
  • 4
  • 33
  • 43
  • Have you considered `Promise.all`. It'd end up looking something like `var p1 = User.filter(paramExists ? args1 : args2), p2 = Data.filter(...); Promise.all([p1, p2]).then(function (user, data) { ... });` – numbers1311407 Jul 29 '16 at 02:06
  • Sounds like you're asking for [conditions in promise chains](http://stackoverflow.com/q/26599798/1048572)? – Bergi Jul 29 '16 at 03:13

3 Answers3

2

You can do something as follows. I am assuming that Data.filter returns a promise as well.

if (paramExists) {
    // call database with this query
    User.filter(/* do something with param */)
        .then(sameCondition);  // omit catch for clarity
} else {
    // call database with this query
    User.filter(/* do something with header */)
        .then(sameCondition);  // omit catch for clarity
}

function sameCondition(user) {
  return Data.filter(/* same in both conditions */)
    .then(function (data) {
      // join data and user
      res.send(joinedData);
  });  // omit catch for clarity
}
Subash
  • 7,098
  • 7
  • 44
  • 70
2

Since the only part that seems to be different between the two branches is what you pass to User.filter(), you can put that value into a local variable in a conditional and then run one version of the code using the variable.

You can also simplify your chained methods too to remove unnecessary nesting:

var arg; 
if (paramExists) {
    arg = ...     // some logic
} else {
    arg = ...     // some different logic
}
// call database with this query
User.filter(arg).then(function (user) {
    return Data.filter(...);
}).then(function (data) {
    // join data and user
    res.send(joinedData);
});  // omit catch for clarity

You could also use a ternary:

var arg = paramExists ? someLogic : someOtherLogic;
// call database with this query
User.filter(arg).then(function (user) {
    return Data.filter(...);
}).then(function (data) {
    // join data and user
    res.send(joinedData);
});  // omit catch for clarity

If you need to access both user and data for sending the response (a little hard to tell in your pseudo code), then you could keep your nesting:

var arg = paramExists ? someLogic : someOtherLogic;
// call database with this query
User.filter(arg).then(function (user) {
    return Data.filter(...).then(function(data) {
        // join data and user
        res.send(joinedData);
    });
});  // omit catch for clarity
jfriend00
  • 683,504
  • 96
  • 985
  • 979
  • I think this might be a problem because the OP needs to join the result of the first promise with the 2nd, and with your chained callback approach the returned user data is out of scope. – numbers1311407 Jul 29 '16 at 02:12
  • @numbers1311407 - I added that option back in. Hard to tell that level of detail in pseudo code some times. Or, they can also share data at the same level with one of [these schemes](http://stackoverflow.com/questions/28714298/how-to-chain-and-share-prior-results-with-promises/28714863#28714863). – jfriend00 Jul 29 '16 at 02:17
  • Actually yes, the second option works. Thank you for that, learning to love promises. – alex Jul 29 '16 at 02:21
1

Do something like this...

var task1 = paramExists ? 
   User.filter(/* do something with param */) :
   User.filter(/* do something with header */)

var doFilter = task1.then(function () {
   return Data.filter(/* same in both conditions */)
})

doFilter.then(function (joinedData) {
   res.send(joinedData);
});
Dmitry Matveev
  • 5,320
  • 1
  • 32
  • 43