Back to main page Traveling Coderman

Resolve a list of promises synchronously

2485 views

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)));
}