語法
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 |
瀏覽器相容性
載入中…