Changing Async/Await to Promises.all to Speed Up API Calls in Node.JSโ€‚by@wendiesun

Changing Async/Await to Promises.all to Speed Up API Calls in Node.JS

image
Wendie Sun HackerNoon profile picture

Wendie Sun

Learning from others and sharing what I found helpful. =)

The Problem

There is a bulk edit feature where the user can multi-select a few records and edit all of them at the same time.

However when updating 50+ records at once, it can take up to 50 seconds and the page freezes. The users were confused during the wait and often left the page early. We want to make it faster.

image

Why the Slowness

The code was written like this:

for (r in records) {
    await update(r)
}

Updating one record makes an API call that takes 500ms - 1s.

And since it iterates over the records and updates them one by one, the time goes up linearly as there are more records to be updated.

Using Promise to Speed Up

Fortunately we don't have to wait for one update to finish before we process the next one.

Promise.all
allows us to make the next update request before the previous one finishes.

This is what we did:

const allPromises = [];
for (r in records) {
   const promise = update(r);
   allPromises.push(promise);
};

await Promise.all(allPromises);

Visually this is what happened when using

async/await
v.s. using
promises
:

image

As we can see, since we are not waiting for each update request to return before making the next one, it saves lots of time.

Be Careful - Promise.all() Is All or Nothing

One thing to keep in mind is that

Promise.all(allPromises)
only resolves after all promises are resolved.

This means if any of the promises are rejected,

await Promise.all(allPromises)
will throw an error.

image

This is not the behaviour I want. In my case, I want to know which records were updated successfully, even if some of them failed.

To achieve this, we used

.then
and
.catch
to make sure the update promises resolve no matter what.

To tell the outcome, we made it resolve to its

id
if succeeded, and
null
if not.ย 

This way we were able to get the ids of the successfully updated records:

const allPromises = [];
for ( r in records) {
    const promise = new Promise((res, rej) => {
        update(t)
            .then(() => { res(r.id) }); # succeed
            .catch(err => { res(null) }); # failed
    });
    promiseList.push(promise);
};

let results = await Promise.all(allPromises);
results = results.map(r => r!==null);

Note that in your case you might want to use something that suits your requirement.

Visually this is what happened now if some update requests failed:

image

And we were able to use the returned array to tell which records were updated successfully.

That's it! We were able to reduce a bulk edit operation of 50+ records from 50+ seconds to less than 5 seconds with this change.ย ๐Ÿ’ช

Thanks for Reading!

I hope this is clear and helpful. If you have any questions please don't hesitate to leave a comment.

Thanks for your time!

Comments

Signup or Login to Join the Discussion

Tags

Related Stories