【问题标题】:Do multiple promises on an array of elements [closed]对一组元素做多个承诺[关闭]
【发布时间】:2017-05-03 09:51:23
【问题描述】:

我有一个 objectIds 列表,我想转到不同的集合并根据每个 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.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)
})

【问题讨论】:

    标签: javascript node.js mongoose promise bluebird


    【解决方案1】:

    用简化的方式重述问题:

    您有一个 ID 数组,对于每个 ID,您想依次调用三个返回承诺的函数 ABC,如下所示:

    • A(id)(无条件)
    • 然后B(id)(无条件)
    • 然后是C(id)(有条件的,取决于B(id)的结果)

    我们可以这样做吗:

    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:沿着承诺链的成功路径传递测试数据

    B,使其返回的承诺将在成功(匿名审查被删除)或预期失败(匿名审查未被删除)时履行,并通过以下方式报告结果一个参数。

    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:沿着承诺链的失败路径传递的测试错误

    写入B,使其返回的承诺将在成功时履行,或在预期失败时拒绝。

    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,因为它更简单、更高效。

    【讨论】:

      【解决方案2】:

      您可以使用Array.reduce() 依次执行您的承诺:

      arrOfObjectIds.reduce(function(promise, objectId) {
        return promise.then(function(result) {
          return removeOperation(objectId)
            .then(firstCheckIfAnonHasTheIdInReviewsArrayIfThereDeleteIt)
            .then(thenCheckIfUserHasTheIdInReviewsArrayIfThereDeleteIt);
        });
      }, Promise.resolve());
      

      这将在数组中一次执行removeOperation -> firstCheck.. -> thenCheck 的链,然后移动到下一项。

      【讨论】:

        【解决方案3】:

        can we doe something like:是的,就是这样,只是第一次返回退出函数

        所以,你可以做类似的事情

        Promise.mapSeries(arrOfObjectIds, function(e){
            return removeOperation(e)
            .then(function() {
                return firstCheckIfAnonHasTheIdInReviewsArrayIfThereDeleteIt(e);
            }).then(function() {
                return thenCheckIfUserHasTheIdInReviewsArrayIfThereDeleteIt(e);
            })
        })
        

        【讨论】:

          猜你喜欢
          • 2016-10-27
          • 2014-04-15
          • 2014-03-24
          • 1970-01-01
          • 2017-03-09
          • 1970-01-01
          • 1970-01-01
          • 2022-01-02
          • 2014-03-22
          相关资源
          最近更新 更多