Resolve a list of promises synchronously
Coding Apr 15, 2022
The JavaScript function Promise.all executes promises in parallel. How to write a function to execute and resolve the results synchronously instead.
TLDR; 🔗
In case you just want the code (no judgment!), here it is.
async function allSynchronously<T>(
resolvables: (() => Promise<T>)[]
): Promise<T[]> {
const results = [];
for (const resolvable of resolvables) {
results.push(await resolvable());
}
return results;
}
Long version 🔗
Let's assume we want to write a function getBooks(ids: string[]): Promise<Book[]>
. For the list of IDs ids: string[]
we want to resolve the associated books Book[]
. There is an endpoint GET /books/:id
. The function getBook(id: string): Promise<Book>
makes that endpoint accessible.
interface Book {
id: string;
}
function getBook(id: string): Promise<Book> {
// GET /books/:id
}
An implementation of getBooks
could use Promise.all
to return a promise of books that resolves once the last endpoint call to GET /books/:id
returns.
function getBooks(ids: string[]): Promise<Book[]> {
return Promise.all(ids.map(getBook));
}
The function Promise.all
runs in parallel. This makes it fast. However, there are situations where you want it to run synchronously, one after the other. The API could be rate-limited or you might want to distribute the load.
For these cases, we can write a synchronous version of Promise.all
. Such a function can not have the signature allSynchronously<T>(promises: Promise<T>[]): Promise<T[]>
. If the function accepted a list of promises as an argument, then at that point in time these promises would already run in parallel. Therefore, the signature accepts a list of zero-argument functions allSynchronously<T>(promises: (() => Promise<T>)[]): Promise<T[]>
async function allSynchronously<T>(
resolvables: (() => Promise<T>)[]
): Promise<T[]> {
const results = [];
for (const resolvable of resolvables) {
results.push(await resolvable());
}
return results;
}
Now, an implementation of getBooks
can use this function allSynchronously
to run the requests synchronously instead of in parallel.
function getBooks(ids: string[]): Promise<Book[]> {
return allSynchronously(ids.map((id) => () => getBook(id)));
}