Array.fromAsync()
语法
js
Array.fromAsync(arrayLike)
Array.fromAsync(arrayLike, mapFn)
Array.fromAsync(arrayLike, mapFn, thisArg)
参数
返回值
描述
Array.fromAsync()
允许你从以下对象中创建数组:
- 异步可迭代对象(如
ReadableStream
和AsyncGenerator
);或者,如果对象不是异步可迭代的, - 可迭代对象(如
Map
和Set
);或者,如果对象是不可迭代的, - 类数组的对象(带有
length
属性和索引元素的对象)。
Array.fromAsync()
迭代异步可迭代对象的方式与 for await...of
很相似。Array.fromAsync()
在行为上与 Array.from()
几乎等价,除了以下几点:
Array.fromAsync()
可以处理异步可迭代对象。Array.fromAsync()
返回一个会兑现为数组实例的Promise
。- 如果使用非异步可迭代对象调用
Array.fromAsync()
,则要添加到数组中的每个元素(无论是否为 Promise)都会先等待其兑现。 - 如果提供了
mapFn
,则其输入和输出会在内部等待兑现。
Array.fromAsync()
和 Promise.all()
都可以将一个 promise 可迭代对象转换为一个数组的 promise。然而,它们有两个关键区别:
Array.fromAsync()
会依次等待对象中产生的每个值兑现。Promise.all()
会并行等待所有值兑现。Array.fromAsync()
惰性迭代可迭代对象,并且不会获取下一个值,直到当前值被兑现。Promise.all()
预先获取所有值并等待它们全部兑现。
示例
从异步可迭代对象创建数组
js
const asyncIterable = (async function* () {
for (let i = 0; i < 5; i++) {
await new Promise((resolve) => setTimeout(resolve, 10 * i));
yield i;
}
})();
Array.fromAsync(asyncIterable).then((array) => console.log(array));
// [0, 1, 2, 3, 4]
从同步可迭代对象创建数组
js
Array.fromAsync(
new Map([
[1, 2],
[3, 4],
]),
).then((array) => console.log(array));
// [[1, 2], [3, 4]]
从产生 promise 的同步可迭代对象创建数组
js
Array.fromAsync(
new Set([Promise.resolve(1), Promise.resolve(2), Promise.resolve(3)]),
).then((array) => console.log(array));
// [1, 2, 3]
从 promise 的类数组对象创建数组
js
Array.fromAsync({
length: 3,
0: Promise.resolve(1),
1: Promise.resolve(2),
2: Promise.resolve(3),
}).then((array) => console.log(array));
// [1, 2, 3]
使用 mapFn
Array.fromAsync()
内部会等待 mapFn
的输入和输出的兑现。
js
function delayedValue(v) {
return new Promise((resolve) => setTimeout(() => resolve(v), 100));
}
Array.fromAsync(
[delayedValue(1), delayedValue(2), delayedValue(3)],
(element) => delayedValue(element * 2),
).then((array) => console.log(array));
// [2, 4, 6]
与 Promise.all() 的比较
Array.fromAsync()
会依次等待对象中产生的每个值兑现。Promise.all()
会并行等待所有值兑现。
js
function* makeAsyncIterable() {
for (let i = 0; i < 5; i++) {
yield new Promise((resolve) => setTimeout(resolve, 100));
}
}
(async () => {
console.time("Array.fromAsync() time");
await Array.fromAsync(makeAsyncIterable());
console.timeEnd("Array.fromAsync() time");
// Array.fromAsync() time: 503.610ms
console.time("Promise.all() time");
await Promise.all(makeAsyncIterable());
console.timeEnd("Promise.all() time");
// Promise.all() time: 101.728ms
})();
没有对同步可迭代对象的错误处理
如果被迭代的对象是同步可迭代对象,并且在迭代时抛出错误,类似于 for await...of
,底层迭代器的 return()
方法将不会被调用,因此迭代器不会被关闭。
js
function* generatorWithRejectedPromises() {
try {
yield 0;
yield Promise.reject(3);
} finally {
console.log("called finally");
}
}
(async () => {
try {
await Array.fromAsync(generatorWithRejectedPromises());
} catch (e) {
console.log("caught", e);
}
})();
// caught 3
// 没有“called finally”信息
如果需要关闭迭代器,则需要使用 for...of
循环,并手动等待每个值兑现。
js
(async () => {
const arr = [];
try {
for (const val of generatorWithRejectedPromises()) {
arr.push(await val);
}
} catch (e) {
console.log("caught", e);
}
})();
// called finally
// caught 3
规范
Specification |
---|
ES Array.fromAsync (2022) # sec-array.fromAsync |
浏览器兼容性
BCD tables only load in the browser