使用 Promise 进行流量控制

Flow control with Promise

我有这段代码:

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});
    });

为什么这段代码的结果是 0,就像 each 在 last then 被触发之前还没有完成?

如果 ReturnsService.getTotalAmount() 是异步的,Bluebird 的 .each() 不会等待它完成它的工作,也不会等待 totalAmount 在没有指导的情况下被修改:

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

如果 getTotalAmount() 本身提供了承诺,则只需要添加 return 即可:

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

否则,应该为它创建一个new Promise()

.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);
        });
    });
})

顺便说一句,迭代以确定单个值(总和等)的场景是另一种方法的意图 - .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 });
});