DEV Community

Cover image for Handle Multiple Promises using Async/Await
Matthew Wang
Matthew Wang

Posted on

8 6

Handle Multiple Promises using Async/Await

In this example below, we loop through an Array of userIDs to fetch information about the user.

A naive approach may be to await each response one by one.

❌ The wrong and slow way

userIDs = ['fooID1', 'fooID2', ...]
const slowMethod = async (userIDs) => {
    const results = [];
    for (let i = 0; i < userIDs.length; i++) {
        const res = await fetch(`https://api.foo.com/users?uid=${userIDs[i]}`)
        const data = await res.json()
        results.push(data);
    }
    return results;
}
await slowMethod(); //O(n) time
Enter fullscreen mode Exit fullscreen mode

✔️ The Fast Way

userIDs = ['fooID1', 'fooID2', ...]
const fastCleanMethod = async (userIDs) => {
    const promises = userIDs.map(async userID => {
        const res = await fetch(`https://api.foo.com/users?uid=${userID}`);
        return await res.json();
    });
    return await Promise.all(promises);
}
await fastCleanMethod(); //O(1) time
Enter fullscreen mode Exit fullscreen mode

🧐 How it works

The fast method takes advantage of the Promise.all() method. The way it works is by fetching all the data first, then using Promise.all() to resolve/reject later.

By doing this, we do not have to wait for each response one by one.

Another Example of two separate fetches

Let's say we want to fetch user data and their entries. Here are two ways to do it.

❌ Fast but Fails Slow

const getUserData = async (userIDs) => {
    const userDataPromise = fetch(`https://api.foo.com/users?uid=${userID}`);
    const userEntriesPromise = fetch(`https://api.foo.com/entries?uid=${userID}`);

    const [userDataRes, userEntriesRes] = [(await userDataPromise).json(), (await userEntriesPromise).json()];
    const [userData, userEntries] = [await userDataRes, await userEntriesRes];
    return {
        ...userData,
        userEntries,
    }
}
Enter fullscreen mode Exit fullscreen mode

This method works well in most cases but if the second Promise is rejected bad things can happen. The reason it fails slow is because if the second Promise is rejected, the first Promise still runs for the whole duration.

Stack Overflow user @T.J. Crowder explains parallel Promise patterns best here.

✔️ Fast and Fails Fast

const getUserData = async (userIDs) => {
    const userDataPromise = fetch(`https://api.foo.com/users?uid=${userID}`);
    const userEntriesPromise = fetch(`https://api.foo.com/entries?uid=${userID}`);

    const [userDataRes, userEntriesRes] = await Promise.all([userDataPromise, userEntriesPromise]);
    const [userData, userEntries] = await Promise.all([userDataRes.json(), userEntriesRes.json()]);
    return {
        ...userData,
        userEntries,
    }
}
Enter fullscreen mode Exit fullscreen mode

We use Promise.all() because when a Promise is rejected, it immediately throws an error without waiting for other Promises.

It may be tempting to use pure async/await for handling multiple Promises but Promise.all() is still our best bet.

Image of Timescale

🚀 pgai Vectorizer: SQLAlchemy and LiteLLM Make Vector Search Simple

We built pgai Vectorizer to simplify embedding management for AI applications—without needing a separate database or complex infrastructure. Since launch, developers have created over 3,000 vectorizers on Timescale Cloud, with many more self-hosted.

Read more

Top comments (0)

Postmark Image

Speedy emails, satisfied customers

Are delayed transactional emails costing you user satisfaction? Postmark delivers your emails almost instantly, keeping your customers happy and connected.

Sign up