alexi2 alexi2 - 4 months ago 9
Javascript Question

DRY up promises in javascript

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?

Answer

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