【问题标题】:Wait for promises inside Promise.all to finish before resolving it等待 Promise.all 中的 Promise 完成,然后再解决它
【发布时间】:2017-09-10 03:11:33
【问题描述】:

我有一个 Promise.all,它执行映射到数组输入的异步函数(如果它不为空),然后将数据解析为先前定义的 Promise:

Promise.all((inputs || []).map(input => {
  return new Promise((resolve, reject) => {
    someAsyncFunc(input)
    .then(intermediateOutput => {
      someOtherAsyncFunc(intermediateOutput )
      .then(output => {
        return Promise.resolve(output )
      })
      .catch(reason=> {
        return Promise.reject(reason)
      })
    })
    .catch(reason => {
      return Promise.reject(reason);
    })
  })
  .then(outputs => {
    resolve(outputs)
  })
  .catch(reason => {
    reject(reason)
  })
}))

在 someAsyncFunc 完成其工作之前,我只会得到空输出。如何让 Promise.all 等待里面的 Promise 完成它们的异步工作?

【问题讨论】:

  • 您对Promise.all() 的工作方式感到非常困惑。它不接受你在第一行代码中声明的回调。它接受一系列承诺。
  • return Promise.all(inputs.map(someAsyncFunc)); 可能是您要找的?
  • @Arthur,是的,但实际上我在 someAsyncFunc 之后还有另一个函数要调用。我将编辑我的代码以显示这一点

标签: javascript promise es6-promise


【解决方案1】:

查看 jfriend 的评论。

someAsyncFuncsomeOtherAsyncFunc 是正确返回承诺的函数 类似return new Promise(/*...*/);

这是没用的:

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

阅读 Promise 文档

一样

.catch(reason=> {
  return Promise.reject(reason)
})

Promise 已经在拒绝,你不需要自己去捕捉和拒绝

为了确保 Promise 是可链接的,你需要返回 Promise

// ...
return new Promise((resolve, reject) => {
  if(inputs == null)
    resolve([]);
  else {
    Promise.all(inputs.map(input => {
      return someAsyncFunc(input)
        .then(someOtherAsyncFunc)
    }))
      .then(resolve)
      .catch(reject)
  }
});

请注意,我宁愿不要将 Promise.all 内联,它会增加视觉混乱:

return new Promise((resolve, reject) => {
  if(inputs == null)
    resolve([]);
  else {
    const myPromises = inputs.map(input => {
      return someAsyncFunc(input)
        .then(someOtherAsyncFunc)
    });
    Promise.all(myPromises)
      .then(resolve)
      .catch(reject)
  }
});

如果你犯了其他错误,它仍然可能失败。

【讨论】:

  • 非常感谢您的意见!很清楚
  • 当我清除一个 var 来创建一个循环 ".map()" 我得到了Objects are not valid as a React child (found: object with keys {_40, _65, _55, _72}). If you meant to render a collection of children, use an array instead.
  • 提出一个新问题 Oliver d
【解决方案2】:

不只是

return Promise.all((inputs || []).map(input =>
 somePromiseFunc(input).then(someOtherPromiseFunc)
);

工作?

您不是第一次使用Promise.all,因为它需要一组承诺作为输入,而不是(resolve, reject) => { ... }

一旦底层承诺之一失败,Promise.all 就会被拒绝,因此您无需尝试围绕catch(error => reject(error) 做一些事情

例子:

const somePromiseFunc = (input) => new Promise((resolve, reject) => {
  setTimeout(() => {
    if (input === 0) { reject(new Error('input is 0')); }
    resolve(input + 1);
  }, 1000);
});

const someOtherPromiseFunc = (intermediateOutput) => new Promise((resolve, reject) => {
  setTimeout(() => {
    if (intermediateOutput === 0) { reject(new Error('intermediateOutput is 0')); }
    resolve(intermediateOutput + 1);
  }, 1000);
});

const f = inputs => {
  const t0 = Date.now()
  return Promise.all((inputs || []).map(input => somePromiseFunc(input).then(someOtherPromiseFunc)))
    .then(res => console.log(`result: ${JSON.stringify(res)} (after ${Date.now() - t0}ms)`))
    .catch(e => console.log(`error: ${e} (after ${Date.now() - t0}ms)`));
};

f(null)
// result: [] (after 0ms)

f([1, 0])
// error: Error: input is 0 (after 1001ms)

f([1, -1])
// error: Error: intermediateOutput is 0 (after 2002ms)

f([1, 2])
// result: [3,4] (after 2002ms)

【讨论】:

    猜你喜欢
    • 2020-06-23
    • 1970-01-01
    • 1970-01-01
    • 2016-12-01
    • 2019-08-31
    • 2020-06-26
    • 2018-11-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多