[英]Use async await with 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>[]”不可分配给类型“number[]”。 类型 'Promise<number> 不可分配给类型 'number'。
我该如何解决? 如何让async await
和Array.map
一起工作?
这里的问题是您正在尝试
await<\/code>一系列承诺而不是承诺。
这不符合您的预期。
当传递给
await<\/code>的对象不是 Promise 时,
await<\/code>会立即按原样返回值,而不是尝试解析它。
因此,由于您在这里传递了一个数组(Promise 对象)而不是 Promise,所以
await<\/code>返回的值就是该数组,它的类型是
Promise<number>[]<\/code> 。
您可能想要做的是在
map<\/code>返回的数组上调用
Promise.all<\/code> ,以便在
await<\/code>之前将其转换为单个 Promise 。
根据
Promise.all<\/code>的 MDN 文档<\/a>:
Promise.all(iterable)<\/code>方法返回一个当可迭代参数中的所有承诺都已解决时解决的承诺,或者以第一个被拒绝的承诺的原因拒绝。
所以在你的情况下:
这将解决您在此处遇到的特定错误。
根据你想要做什么,你也可以考虑使用
Promise.allSettled<\/code><\/a> 、
Promise.any<\/code><\/a>或
Promise.race<\/code><\/a>代替
Promise.all<\/code> ,尽管在大多数情况下(几乎肯定包括这个)
Promise.all<\/code>会成为你想要的那个。
下面的解决方案可以一起正确使用 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(n => calc(n));
const results = await Promise.all(unresolvedPromises);
};
asyncFunc();
还有代码笔。
请注意,我们只“等待” Promise.all。 我们多次调用 calc 而没有“等待”,我们会立即收集一系列未解决的 Promise。 然后 Promise.all 等待所有它们的解析并按顺序返回一个包含解析值的数组。
如果您使用的不是原生 Promises 而是 Bluebird,还有另一种解决方案。
您也可以尝试使用Promise.map()<\/a> ,混合 array.map 和 Promise.all
在你的情况下:
var arr = [1,2,3,4,5];
var results: number[] = await Promise.map(arr, async (item): Promise<number> => {
await callAsynchronousOperation(item);
return item + 1;
});
如果映射到 Promise 数组,则可以将它们全部解析为数字数组。 请参阅Promise.all 。
这是最简单的方法。
await Promise.all(
arr.map(async (element) => {
....
})
)
您可以使用:
for await (let resolvedPromise of arrayOfPromises) {
console.log(resolvedPromise)
}
我建议使用上面提到的 Promise.all,但如果你真的想避免这种方法,你可以做一个 for 或任何其他循环:
const arr = [1,2,3,4,5];
let resultingArr = [];
for (let i in arr){
await callAsynchronousOperation(i);
resultingArr.push(i + 1)
}
import { map } from 'modern-async'
...
const result = await map(myArray, async (v) => {
...
})
我在 BE 方面有一项任务,即从 repo 中查找所有实体,并添加一个新的属性 url 并返回到控制器层。 这就是我实现它的方式(感谢 Ajedi32 的回应):
async findAll(): Promise<ImageResponse[]> {
const images = await this.imageRepository.find(); // This is an array of type Image (DB entity)
const host = this.request.get('host');
const mappedImages = await Promise.all(images.map(image => ({...image, url: `http://${host}/images/${image.id}`}))); // This is an array of type Object
return plainToClass(ImageResponse, mappedImages); // Result is an array of type ImageResponse
}
这可能会帮助某人。
const APISimulator = (v) => new Promise((resolve, reject) => {
setTimeout(() => {
resolve({ data: v });
}, v * 100);
});
const arr = [7, 6, 5, 1, 2, 3];
const res = () => arr.reduce(async (memo, v, i) => {
const results = await memo;
console.log(`proccessing item-${i + 1} :`, v)
await APISimulator(v);
console.log(`completed proccessing-${i + 1} :`, v)
return [...results, v];
}, []);
res().then(proccessed => console.log(proccessed))
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.