Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Flow control with Promise

I have this piece of code:

var totalAmount = 0;

Returns.find().populate("products")
    .then(function (returns){
        return returns;
    })

    .each(function (returns){
        ReturnsService.getTotalAmount(returns.products, function(err, result){
            totalAmount = totalAmount + result;
        });
    })

    .then(function (){
        return res.send({total : totalAmount});
    });

Why is the result of this code is 0, it's like the each is not being finished before the last then is being fired?

like image 566
Emmanuel Campos Avatar asked Dec 03 '25 01:12

Emmanuel Campos


1 Answers

If ReturnsService.getTotalAmount() is asynchronous, Bluebird's .each() won't wait for that to complete its work and for totalAmount to be modified without some guidance:

If the iterator function returns a promise or a thenable, then the result of the promise is awaited, before continuing with next iteration.

If getTotalAmount() provides a promise itself, a return is all that needs to be added:

.each(function (returns){
    return ReturnsService.getTotalAmount(returns.products, ...);
})

Otherwise, a new Promise() should be created for it:

.each(function (returns) {
    return new Promise(function (resolve, reject) {
        ReturnsService.getTotalAmount(returns.products, function(err, result){
            if (err)
                return reject(err);

            totalAmount = totalAmount + result;
            resolve(totalAmount);
        });
    });
})

As as aside, the scenario of iterating to determine a single value (sum total, etc.) is the intent of another method -- .reduce().

.reduce(function (runningTotal, returns) {
    return new Promise(function (resolve, reject) {
        ReturnsService.getTotalAmount(returns.products, function(err, result){
            if (err)
                return reject(err);

            resolve(runningTotal + result); // resolve with new total
        });
    });
}, 0 /* initial value */)

// combined total will be passed as the argument
.then(function (totalAmount) {
    return res.send({ total : totalAmount });
});
like image 138
Jonathan Lonowski Avatar answered Dec 04 '25 16:12

Jonathan Lonowski



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!