javascript - 对一组元素执行多个 Promise

标签 javascript node.js mongoose promise bluebird

我有一个 objectId 列表,我想访问不同的集合并根据每个 Id 进行操作。我更喜欢一个接一个地执行操作(按顺序)

var removeOperation = function(objectified){
   return Comps.findOne({reviews : objectified}).populate([{ path: "reviews", match : {_id : objectified}}])

}
var firstCheckIfAnonHasTheIdInReviewsArrayIfThereDeleteIt = function(objectified){
    var query = {reviews : objectified};
    var update = {$pull : {reviews : objectified}};
    var option = {new :true};
    return Anon.findOneAndUpdate(query, update, option );
};
var thenCheckIfUserHasTheIdInReviewsArrayIfThereDeleteIt = function(objectified){
    var query = {reviews : objectified};
    var update = {$pull : {reviews : objectified}};
    var option = {new :true};
    return User.findOneAndUpdate(query, update, option );
}

我正沿着这条路走:

Promise.mapSeries(arrOfObjectIds, function(e){
    return removeOperation(e);
})
.then(function(results){
    console.log(results);
    var map = results.map(function(e){
        // return e.reviews[0]
        return e

    })
    console.log("map : ", map)
    return Promise.resolve(map);
})
.then(function(compDocs){
    console.log("compDocs: ",compDocs)
    Promise.mapSeries(compDocs,  function(compDoc){
        return updateCompAndRemoveReviewFromArray(compDoc) // I know it's not show. It's another promise I use
    })

}).then(function(returned){
    return Reviews.remove({_id : {$in : arrOfObjectIds }})
})
.then(function(){
  I wanted to do firstCheckIfAnonHasTheIdInReviewsArrayIfThereDeleteIt on the array of object Ids to delete the review from the array. Also if we succesfully removed the array here we should not have to go to the next user 
  promise which deletes a users review since if we deleted in Anon it won't be in User. since there is only one review ID possible per review.
})
.then(function(){
    //if there was no review pulled from the Anon reviews Array. that means it's in the users review and we should do this promise 

       thenCheckIfUserHasTheIdInReviewsArrayIfThereDeleteIt()
})

也许你可以告诉我如何使用 mapSeries在一组元素上,这样它就不会做出一个 promise ,而是做出多个 promise 。

我们可以做这样的事情吗:

Promise.mapSeries(arrOfObjectIds, function(e){
    return removeOperation(e);
    return firstCheckIfAnonHasTheIdInReviewsArrayIfThereDeleteIt(e)// extra credit: check if this was successful (review was pulled). If it wasn't got to next one.
    return thenCheckIfUserHasTheIdInReviewsArrayIfThereDeleteIt(e)
})

最佳答案

用简化的术语重述问题:

You have an array of IDs and for each ID in turn you want to call three promise-returning functions, A, B and C as follows :

  • A(id) (unconditionally)
  • then B(id) (unconditionally)
  • then C(id) (conditionally, depending on the outcome of B(id))
<小时/>

Can we do something like:

Promise.mapSeries(arrOfObjectIds, function(e){
    return removeOperation(e);
    return firstCheckIfAnonHasTheIdInReviewsArrayIfThereDeleteIt(e)// extra credit: check if this was successful (review was pulled). If it wasn't got to next one.
    return thenCheckIfUserHasTheIdInReviewsArrayIfThereDeleteIt(e)
})

是的,尽管不太喜欢建议的代码。

首先,您需要对 B 报告其结果的方式进行设计选择。该问题暗示 B 的结果是“成功”与“失败”的情况,但这并不是建模的唯一方法。

选项 1:测试沿着 promise 链的成功路径传递的数据

编写B,使其返回的 promise 将在成功(匿名评论被删除)或预期失败(匿名评论未删除)时实现,并报告通过参数的方式得出结果。

var B = function(objectified) {
    var query = {reviews: objectified};
    var update = {$pull: {reviews: objectified}};
    var option = {new :true};
    return Anon.findOneAndUpdate(query, update, option).exec();
};

然后你会写:

Promise.mapSeries(arrOfObjectIds, function(id) {
    return A(id).then(function() {
        return B(id);
    }).then(function(item) { // item will be `null` if B(id) found nothing.
        return item || C(id);
    }).catch(function(error) {
        // If anything went wrong, catch the error and log it.
        console.log(error); 
        // By not re-throwing the error, the mapseries() is allowed to continue.
    });
});

选项 2:沿着 promise 链的失败路径传递测试错误

编写B,使其返回的 promise 将在成功时实现,或在预期失败时拒绝。

var B = function(objectified) {
    var query = {reviews: objectified};
    var update = {$pull: {reviews: objectified}};
    var option = {new :true};
    return Anon.findOneAndUpdate(query, update, option).exec().then(function(item) {
        return item || Promise.reject(new Error('not found'));
    });
};

然后你会写:

Promise.mapSeries(arrOfObjectIds, function(id) {
    return A(id).then(function() {
        return B(id).catch(function(error) {
            // Here, you have to discriminate between the "expected error" and any unexpected errors.
            if(error.message === 'not found') {
                return C(id);
            } else {
                throw error; // unexpected error - rethrow it
            }
        });
    }).catch(function(error) {
        // If anything went wrong, catch the error and log it.
        console.log(error); 
        // By not re-throwing the error, the overall mapseries() is allowed to continue.
    });
});

在这两个选项中:

  • 要返回真正的 Promise,请在 ABC 中使用 .exec()。 (据我了解 Mongoose,没有 exec() 你会得到一些有 .then() 方法的东西,但这不是一个成熟的 Promise)。
  • 如果您希望整个序列在出现第一个错误时停止,请在记录错误后重新抛出该错误,或​​者完全省略最后的 catch()
  • 可以非常简单地在条件阶段之前或之后添加更多无条件阶段。

对我来说,选项 2 更符合逻辑,但我可能会选择选项 1,因为它更简单、更高效。

关于javascript - 对一组元素执行多个 Promise,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41204054/

相关文章:

javascript - 如何使用 node-pty 和 xterm 在终端中不打印命令?

javascript - 使用变量获取位置然后修改mongodb中的特定对象

Javascript 值从 Web 服务返回,但除非使用断点,否则不会显示

javascript - 如何从网站编辑div内的代码?

mysql - 尝试使用 sequelize 搜索两列

node.js - PM2集群模式只启动一个实例

mongodb - 根据精益查询的结果创建 Mongoose 模型

node.js - TypeError : db. 模型不是函数

javascript - Backbone.localStorage + RequireJS : Not working?

javascript - 尝试使用express-load和express 4