Node.js:异步任务的顺序执行

时间:2017-04-04 22:41:00

标签: node.js asynchronous promise q

我有一个类似于:

的对象数组
let builds = [
    { status: "Failed"},
    { status: "Completed"},
    { status: "Building"},
    { status: "Building"},
    { status: "Failed"},
    { status: "Cancelled"},
   ...
]

元素的数量会有所不同,每个元素的status也会有所不同,最小数组大小为零。

我需要编写一个函数:

  • 遍历数组并查找status Building
  • 的所有项目
  • 将这些项目的status更新为Cancelled
  • 如果不再出现Building,请在数组中按下类似于{ status: "Building" }的新项目

问题是数组存储在MongoDB中,因此需要以异步方式将每个操作持久化到DB。我正在使用Q承诺。

我此刻的尝试看起来像这样:

let count=0;  // Keep track of how many "builds" in "Building" state

module.getAllBuilds((builds) => {
    builds.forEach((build) => {
        if (build.status == "Building") {
             count++;
             module.cancelBuild(build)
             .then(() => {
                 if (!--count) {  // When counter is zero, all builds have been dealt with.
                     module.newBuild();
                     return;
                 }
              })
        }
     })
     module.newBuild();   // Get here if the build array is empty or no builds in "Building" state
})

我正在使用count变量来跟踪Building状态中的条目数,就像堆栈一样。当堆栈为空时,我继续创建新构建。

麻烦的是,我必须在两个地方之一调用module.newBuild(),具体取决于是否有任何版本处于Building状态。

有没有更好的方法来实现这个?

1 个答案:

答案 0 :(得分:0)

首先使用Array#reduce过滤构建数组,然后使用module.getAllBuilds((builds) => builds.filter(build => build.status == 'Building').reduce((promise, build) => promise.then(()=> module.cancelBuild(build)), Promise.resolve()) .then(() => module.newBuild())) ,您可以按如下方式简化代码

module.getAllBuilds((builds) => 
    builds.filter(build => build.status == 'Building')
    .reduce(
        (promise, build) => promise.then(() => module.cancelBuild(build)), 
        Promise.resolve()
    )
.then(() => module.newBuild()))

或者,试图让它更具可读性(和失败):p

module.getAllBuilds(function (builds) {
    return builds.filter(function (build) {
        return build.status == 'Building';
    }).reduce(function (promise, build) {
        return promise.then(function () {
            return module.cancelBuild(build);
        });
    }, Promise.resolve()).then(function () {
        return module.newBuild();
    });
});

或转换后的ES5版本

module.newBuild()

注意:即使builds

中没有“建筑物”,也会调用def letter_count(str) counts = Hash.new(0) str.split("").each{|letter| counts[letter] += 1 unless letter == ""} counts end letter_count('a cat') # => {"a"=>2, " "=>1, "c"=>1, "t"=>1}