How to Use Array.fromAsync in JavaScript
Array.fromAsync() is a built-in static method in
JavaScript that creates a new array from an async iterable, a sync
iterable, or an array-like object containing promises. This article
explains how Array.fromAsync() operates, breaks down its
syntax and parameters, details its sequential execution mechanism, and
provides practical code examples demonstrating how it simplifies
asynchronous data processing.
What is Array.fromAsync?
Array.fromAsync() acts as the asynchronous counterpart
to Array.from(). While Array.from() works
strictly with synchronous iterables and array-like objects,
Array.fromAsync() handles objects that yield promises or
implement the Symbol.asyncIterator protocol. Instead of
returning an array immediately, it returns a Promise that
resolves to a newly created array containing all resolved values.
Syntax and Parameters
The method accepts up to three arguments:
Array.fromAsync(asyncIterable, mapFn, thisArg)asyncIterable: The async iterable, sync iterable, or array-like object to convert into an array.mapFn(optional): A mapping function to call on every element before adding it to the array. IfmapFnreturns a promise, it will be awaited automatically.thisArg(optional): The value to use asthiswhen executingmapFn.
How Array.fromAsync Builds Arrays Step-by-Step
When Array.fromAsync() is invoked, it processes values
sequentially using the following steps:
- Iterate: It retrieves the iterator from the
provided source (prioritizing
Symbol.asyncIterator, then falling back toSymbol.iterator). - Await Values: It reads items one by one. If an item
is a promise,
Array.fromAsync()pauses execution until that promise fulfills. - Map Elements: If a mapping function
(
mapFn) is provided, the resolved item is passed to it. If the mapping function returns a promise, that promise is also awaited. - Collect: The final value is appended to the resulting internal array.
- Resolve or Reject: Once the iterator completes
(
done: true), the main promise resolves with the populated array. If any iteration step, promise, or mapping function rejects, the returned promise immediately rejects with that error.
Practical Examples
1. Converting an Async Generator
Async generators yield values asynchronously.
Array.fromAsync() can collect all yielded results into a
standard array:
async function* fetchNumbers() {
yield 1;
yield 2;
yield 3;
}
const numbers = await Array.fromAsync(fetchNumbers());
console.log(numbers); // Output: [1, 2, 3]2. Resolving an Array of Promises
Unlike Array.from(), which would leave promises
unresolved inside the resulting array, Array.fromAsync()
awaits each promise:
const promiseArray = [
Promise.resolve("apple"),
Promise.resolve("banana"),
Promise.resolve("cherry")
];
const fruits = await Array.fromAsync(promiseArray);
console.log(fruits); // Output: ['apple', 'banana', 'cherry']3. Using an Async Mapping Function
You can transform items during iteration, even when the transformation itself is asynchronous:
const userIds = [1, 2, 3];
async function fetchUserName(id) {
return `User_${id}`;
}
const users = await Array.fromAsync(userIds, async (id) => {
return await fetchUserName(id);
});
console.log(users); // Output: ['User_1', 'User_2', 'User_3']Array.fromAsync vs. Promise.all
While Promise.all(array.map(...)) executes promises
concurrently, Array.fromAsync() consumes iterables
sequentially. This sequential nature is critical when working with
streams or async generators where the next value depends on the previous
operation completing first, or when you need to avoid overwhelming a
system with concurrent network requests.