【问题标题】:Node.js: Sequential execution of asynchronous tasksNode.js:异步任务的顺序执行
【发布时间】:2017-08-30 08:13:13
【问题描述】:

我有一个对象数组,类似于:

let builds = [
    { status: "Failed"},
    { status: "Completed"},
    { status: "Building"},
    { status: "Building"},
    { status: "Failed"},
    { status: "Cancelled"},
   ...
]

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

我需要编写一个函数:

  • 遍历数组并查找具有statusBuilding 的任何项目
  • 将这些项目的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 状态。

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

【问题讨论】:

  • 我认为您了解您的代码“按顺序”执行异步任务?
  • 是的,目的是按顺序执行

标签: node.js asynchronous promise q


【解决方案1】:

首先过滤 builds Array 中的“Building” - 然后使用Array#reduce,您可以将代码简化如下

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((builds) => 
    builds.filter(build => build.status == 'Building')
    .reduce(
        (promise, build) => promise.then(() => module.cancelBuild(build)), 
        Promise.resolve()
    )
.then(() => module.newBuild()))

或者转译的 ES5 版本

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

注意:即使builds 中没有“建筑物”,module.newBuild() 也会被调用

【讨论】:

  • 第一个 sn-p 中 reduce 参数的缩进吓坏了我……
  • 是的,我也是 - 整个代码最初是两行,我试图让它更具可读性但失败了:p 如果你知道如何更好地“格式化”它,请随意编辑@Bergi
  • 哇,好深。它肯定会勾选“简短而简洁”的框。我不是 100% 清楚你是如何使用 reduce() 的。我首先使用 filter(),然后使用 reduce() 的 args,但 reduce() 的主体有点巫术。是否为下一次迭代返回“Promise.resolve()”?
  • reduce 是一种常用的获取数组的方式,或多或少地把它变成一个promise链
  • 我只是让它更加简洁,因为我意识到你不需要所有module.cancelBuild 承诺中的results
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-08-19
  • 1970-01-01
  • 1970-01-01
  • 2012-06-29
  • 1970-01-01
  • 1970-01-01
  • 2022-08-11
相关资源
最近更新 更多