语法
Array.fromAsync(items)
Array.fromAsync(items, mapFn)
Array.fromAsync(items, mapFn, thisArg)
参数
items-
一个要转换为数组的异步可迭代对象、可迭代对象或类数组对象。
mapFn可选-
一个用于调用数组中每个元素的函数。如果提供了此参数,则添加到数组中的每个值都将首先通过此函数,并且
mapFn的返回值将添加到数组中(在await之后)。该函数将使用以下参数调用: thisArg可选-
执行
mapFn时用作this的值。
返回值
描述
Array.fromAsync() 允许你从以下对象创建数组:
- 异步可迭代对象(例如
ReadableStream和AsyncGenerator);或者,如果对象不是异步可迭代对象,则为: - 可迭代对象(例如
Map和Set);或者,如果对象不是可迭代对象,则为: - 类数组对象(具有
length属性和索引元素的那些对象)。
Array.fromAsync() 以非常类似于 for await...of 的方式迭代异步可迭代对象。如果 items 是异步可迭代对象或同步可迭代对象,则 Array.fromAsync(items) 通常等同于以下代码:
const result = [];
for await (const element of items) {
result.push(element);
}
在行为上,Array.fromAsync() 几乎等同于 Array.from(),但有以下区别:
Array.fromAsync()处理异步可迭代对象。Array.fromAsync()返回一个Promise,该 Promise 实现为数组实例。- 如果使用非异步可迭代对象调用
Array.fromAsync(),则添加到数组的每个元素都会先被await。 - 如果提供了
mapFn,其输出也会在内部被await。
Array.fromAsync() 和 Promise.all() 都可以将 Promise 可迭代对象转换为 Promise 数组。但是,它们之间存在两个关键区别:
Array.fromAsync()顺序等待可迭代对象生成的每个值。Promise.all()并发等待所有值。Array.fromAsync()惰性迭代可迭代对象,直到当前值稳定后才检索下一个值。Promise.all()提前检索所有值并等待它们全部完成。
示例
从异步可迭代对象创建数组
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]
当 items 是一个异步可迭代对象,其中每个结果的 value 本身也是一个 Promise 时,这些 Promise 会被添加到结果数组中,而不会被 await。这与 for await...of 的行为一致。
function createAsyncIter() {
let i = 0;
return {
[Symbol.asyncIterator]() {
return {
async next() {
if (i > 2) return { done: true };
i++;
return { value: Promise.resolve(i), done: false };
},
};
},
};
}
Array.fromAsync(createAsyncIter()).then((array) => console.log(array));
// (3) [Promise, Promise, Promise]
从同步可迭代对象创建数组
Array.fromAsync(
new Map([
[1, 2],
[3, 4],
]),
).then((array) => console.log(array));
// [[1, 2], [3, 4]]
从生成 Promise 的同步可迭代对象创建数组
Array.fromAsync(
new Set([Promise.resolve(1), Promise.resolve(2), Promise.resolve(3)]),
).then((array) => console.log(array));
// [1, 2, 3]
从 Promise 的类数组对象创建数组
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
当 items 是同步可迭代对象或类数组对象时,Array.fromAsync() 会在内部 await mapFn 的输入和输出。
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]
在异步可迭代对象中使用 mapFn
当 items 是异步可迭代对象时,mapFn 的输入不会被 await,但输出会被 await。使用与上面相同的 createAsyncIter 函数:
Array.fromAsync(createAsyncIter(), async (element) => (await element) * 2).then(
(array) => console.log(array),
);
// [2, 4, 6]
有趣的是,这意味着 Array.fromAsync(createAsyncIter()) 不等同于 Array.fromAsync(createAsyncIter(), (element) => element),因为前者会 await 每个生成的值,而后者则不会。
Array.fromAsync(createAsyncIter(), (element) => element).then((array) =>
console.log(array),
);
// [1, 2, 3]
与 Promise.all() 的比较
Array.fromAsync() 顺序等待可迭代对象生成的每个值。Promise.all() 并发等待所有值。
function* makeIterableOfPromises() {
for (let i = 0; i < 5; i++) {
yield new Promise((resolve) => setTimeout(resolve, 100));
}
}
(async () => {
console.time("Array.fromAsync() time");
await Array.fromAsync(makeIterableOfPromises());
console.timeEnd("Array.fromAsync() time");
// Array.fromAsync() time: 503.610ms
console.time("Promise.all() time");
await Promise.all(makeIterableOfPromises());
console.timeEnd("Promise.all() time");
// Promise.all() time: 101.728ms
})();
同步可迭代对象没有错误处理
与 for await...of 类似,如果正在迭代的对象是同步可迭代对象,并且在迭代过程中抛出错误,则不会调用底层迭代器的 return() 方法,因此迭代器不会被关闭。
function* generatorWithRejectedPromises() {
try {
yield 0;
yield Promise.reject(new Error("error"));
} finally {
console.log("called finally");
}
}
(async () => {
try {
await Array.fromAsync(generatorWithRejectedPromises());
} catch (e) {
console.log("caught", e);
}
})();
// caught Error: error
// No "called finally" message
如果你需要关闭迭代器,你需要改用 for...of 循环,并自己 await 每个值。
(async () => {
const arr = [];
try {
for (const val of generatorWithRejectedPromises()) {
arr.push(await val);
}
} catch (e) {
console.log("caught", e);
}
})();
// called finally
// caught 3
规范
| 规范 |
|---|
| ES Array.fromAsync # sec-array.fromAsync |
浏览器兼容性
加载中…