Array.fromAsync()
Baseline 2024
Newly available
Since January 2024, this feature works across the latest devices and browser versions. This feature might not work in older devices or browsers.
语法
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