具有异步/等待功能的 map() 函数

新手上路,请多包涵

有很多关于 async/await 在 javascript 映射函数中的行为的主题,但是,下面两个示例中的详细解释会很好:

   const resultsPromises = myArray.map(async number => {
    return await getResult(number);
  });

   const resultsPromises = myArray.map(number => {
    return getResult(number);
  });

编辑:这当然是一个虚构的案例,所以刚刚开始辩论,映射函数为什么、如何以及何时应该等待 await 关键字。解决方案如何修改这个例子,调用 Promise.all() 不是这个问题的目的。

getResult 是一个异步函数

原文由 user9274045 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1k
2 个回答

其他答案已经很好地涵盖了您的示例行为的细节,但我想 尝试 更简洁地说明它。

 const resultsPromises = myArray.map(async number => {
  return await getResult(number);
});

 const resultsPromises = myArray.map(number => {
  return getResult(number);
});

  1. Array.prototype.map 同步循环一个数组并将每个元素转换为其回调的返回值。

  2. 这两个示例 都返回 Promise

    • async 函数 总是 返回 Promise

    • getResult 返回一个 Promise

    • 因此,如果没有错误,您可以在伪代码中将它们视为:

 const resultsPromises = myArray.map(/* map each element to a Promise */);

  1. 正如 zero298 所述alnitak 所展示的那样,这非常快(同步地)按顺序开始每个承诺;然而,由于它们是并行运行的,每个 promise 都会按照他们认为合适的方式解决/拒绝,并且可能不会按顺序解决(履行或拒绝)。

  2. 要么并行运行承诺并使用 Promise.all 收集结果,要么使用 for * 循环Array.prototype.reduce 顺序运行它们。

或者,您可以使用我维护 的可链式异步 JavaScript 方法 的第三方模块来清理并——也许——使代码符合你对 异步映射 操作可能如何工作的直觉:

 const delay = ms => new Promise(resolve => setTimeout(resolve, ms));

const getResult = async n => {
  await delay(Math.random() * 1000);
  console.log(n);
  return n;
};

(async () => {
  console.log('parallel:');
  await AsyncAF([1, 2, 3]).map(getResult).then(console.log);

  console.log('sequential:');
  await AsyncAF([1, 2, 3]).series.map(getResult).then(console.log)
})();
 <script src="https://unpkg.com/async-af@7.0.12/index.js"></script>

原文由 Scott Rudiger 发布,翻译遵循 CC BY-SA 4.0 许可协议

async/await 当你想通过删除 .then() 回调来扁平化你的代码或者如果你想隐式返回一个 Promise 时很有用:

 const delay = n => new Promise(res => setTimeout(res, n));

async function test1() {
  await delay(200);
  // do something usefull here
  console.log('hello 1');
}

async function test2() {
  return 'hello 2'; // this returned value will be wrapped in a Promise
}

test1();
test2().then(console.log);

但是,在您的情况下,您没有使用 await 来替换 .then() ,也没有使用它来返回隐式 Promise,因为您的函数已经返回了 Promise。所以他们不是必需的。

并行执行所有 Promise

如果您想并行运行所有 Promise,我建议简单地返回 getResultmap() 的结果并生成一个 Promises 数组。 Promise 将按顺序启动,但最终会并行运行。

 const resultsPromises = indicators.map(getResult);

然后你可以等待所有的承诺并使用 Promise.all() 获得解决的结果:

 const data = [1, 2, 3];

const getResult = x => new Promise(res => {
  return setTimeout(() => {
    console.log(x);
    res(x);
  }, Math.random() * 1000)
});

Promise.all(data.map(getResult)).then(console.log);

Promise 的顺序执行

但是,如果你想顺序运行每个 Promise 并等待前一个 Promise 解决后再运行下一个,那么你可以使用 reduce()async/await 像这样:

 const data = [1, 2, 3];

const getResult = x => new Promise(res => {
  return setTimeout(() => {
    console.log(x);
    res(x);
  }, Math.random() * 1000)
});

data.reduce(async (previous, x) => {
  const result = await previous;
  return [...result, await getResult(x)];
}, Promise.resolve([])).then(console.log);

原文由 jo_va 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题