将异步等待与 Array.map 一起使用

新手上路,请多包涵

给定以下代码:

var arr = [1,2,3,4,5];

var results: number[] = await arr.map(async (item): Promise<number> => {
        await callAsynchronousOperation(item);
        return item + 1;
    });

这会产生以下错误:

TS2322:类型“Promise[]”不可分配给类型“number[]”。

类型 ‘Promise 不可分配给类型 ‘number’。

我该如何解决?如何使 async awaitArray.map 一起工作?

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

阅读 819
2 个回答

这里的问题是您正在尝试 await 一系列承诺而不是承诺。这不符合您的预期。

当传递给 await 的对象不是 Promise 时, await 会立即按原样返回值,而不是尝试解析它。因此,由于您在这里传递了一个数组(Promise 对象)而不是 Promise,所以 await 返回的值就是该数组,它的类型是 Promise<number>[]

您可能想要做的是在 map 返回的数组上调用 Promise.all ,以便在 await 之前将其转换为单个 Promise 。

根据 Promise.all 的 MDN 文档

Promise.all(iterable) 方法返回一个可以解析的 Promise

当可迭代参数中的所有承诺都已解决时,或

以第一个通过的 promise 的原因拒绝。

所以在你的情况下:

 var arr = [1, 2, 3, 4, 5];

 var results: number[] = await Promise.all(arr.map(async (item): Promise<number> => {
 await callAsynchronousOperation(item);
 return item + 1;
 }));

这将解决您在此处遇到的特定错误。

根据你想要做什么,你也可以考虑使用 Promise.allSettledPromise.anyPromise.race 代替 Promise.all ,尽管在大多数情况下(几乎肯定包括这个) Promise.all 会成为你想要的那个。

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

下面的解决方案将 async await 和 Array.map 一起正确使用。并行、异步处理数组的所有元素并保持顺序:

 const arr = [1, 2, 3, 4, 5, 6, 7, 8];

const randomDelay = () => new Promise(resolve => setTimeout(resolve, Math.random() * 1000));

const calc = async n => {
  await randomDelay();
  return n * 2;
};

const asyncFunc = async() => {
  const unresolvedPromises = arr.map(calc);
  const results = await Promise.all(unresolvedPromises);
  document.write(results);
};

document.write('calculating...');
asyncFunc();

还有 代码笔

请注意,我们只“等待”Promise.all。我们在没有“等待”的情况下多次调用 calc,我们立即收集了一系列未解决的承诺。然后 Promise.all 等待所有这些解析并按顺序返回一个包含解析值的数组。

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

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