Promise.all()不等待异步进程

时间:2017-08-29 16:20:52

标签: node.js asynchronous promise es6-promise

在node.js中,我试图遍历一些项目,为每个项目完成一个异步过程,然后在下一个项目启动之前等待每个项目完成。我必须做错事,因为Promise.all()不等待任何异步进程完成!我的代码如下:

getChildLessons() {

 return new Promise((resolve, reject) => {

  Promise.all(

    //nested for loop is needed to get all information in object / arrays
   this.lessons.levels.map((item, i) => {

      item.childlevels.map((childItem, iChild) => {

        return ((i, iChild) => {

          //return async process with Promise.resolve();
          return this.horseman
          .open(childItem.url)
          .html()
          .then((html) => {
            //adding some information to an array
          })
          .then(() => {
              return Promise.resolve();
          }).catch((err) => {
            reject(err);
          });

        })(i, iChild);

      });
  })

  // Promise.all().then()
).then(() => {
  resolve(this.lesson);
})
.catch((err) => {
  console.log(err);
});
});
}

我对与node.js的异步相当新,所以如果可能的话,请你提供一个明确的例子。

3 个答案:

答案 0 :(得分:1)

需要修复的两个问题才能使其发挥作用:

  • 提供给外部map调用的回调没有return语句,因此map创建了一个数组,其中所有元素都是undefined。您需要return child.items.map的结果,即一系列承诺。
  • 修复上述内容后,外部map将返回一个数组数组。需要将2D数组的承诺展平为一系列简单的承诺。您可以使用[].concat和扩展语法来执行此操作。

所以你的代码的第一行应该成为:

Promise.all(
    [].concat(...this.lessons.levels.map((item, i) => {
        return item.childlevels.map((childItem, iChild) => {

在适当的位置添加一个右括号 - 关闭concat(的参数列表。

其他一些评论:

  • 以下代码无用:

                .then(() => {
                    return Promise.resolve();
                })
    

    根据定义调用.then的承诺在调用回调时解决。要在此刻返回已解决的承诺,不会添加任何有用的内容。要返回调用.then的承诺就好了。您只需从链中删除上述.then来电即可。

  • 在结束时,您拨打resolve(this.lesson)。这是promise constructor anti pattern的一个例子。您不应该创建新的Promise,而是返回Promise.all调用的结果,并在其.then调用返回 this.lesson内,以便它成为承诺值。

链接所有承诺

要链接所有承诺而不是使用Promise.all,最简单的方法是使用async/await语法。像这样:

async getChildLessons() {
    this.lessons.levels.forEach((item, i) => {
        item.childlevels.map((childItem, iChild) => {
            ((i, iChild) => {
                let html = await this.horseman
                    .open(childItem.url)
                    .html();
                    .catch((err) => {
                        throw(err); // throw instead of reject
                    });
                //adding some information to an array
            })(i, iChild);
        });
    })
    return this.lesson;
}

答案 1 :(得分:0)

也许尝试做这样的事情?

let firstPromise = new Promise((resolve,reject) => {
    // your logic/code
})

//add more promises you want into array if u want


 Promise.all([firstPromise])
.then((response) => {
    //do stuff with response
})
.catch((error) => {
    //do stuff with error
})

答案 2 :(得分:0)

以下代码行无法返回任何内容。您正在尝试将未定义的数组传递给Promise.all

this.lessons.levels.map((item, i) => {...})

但是,您的代码还有其他几个问题。下面的块完全没必要。除了在代码中添加额外的块之外,它几乎什么都不做。

return ((i, iChild) => {...})(i, iChild);

您无需从主函数返回PromisePromise.all()的结果是Promise

考虑到上述情况,这是一段代码片段。

// an array of Promises
var levelPromises = this.lessons.levels.map((item, i) => {

    var childPromises = item.childlevels.map((childItem, iChild) => {
        return this.horseman.open(childItem.url)
        //...
    })

    return Promise.all(childPromises)
})

return Promise.all(levelPromises)