Handle Multiple Promises using Async/Await

matowang

Matthew Wang

Posted on May 7, 2022

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.

💖 💪 🙅 🚩
matowang
Matthew Wang

Posted on May 7, 2022

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related