Running promises sequentially

Today's JavaScript is asynchronous. Like, all of it. If a few years ago, there were a lot of discussions about data transformations. Today's most important topics are all about, should app await, or respond instantly to the user and redraw later when the information is available.

Here's a story about the error I've got when I was running a few of ImageMagick's conversions using a Firebase cloud function:

Error: memory limit exceeded.

So thumbnails generation is using too much memory. And if converting a single image is OK, then multiple images are probably processed in parallel. Here's the code that I was using:

return Promise.all(files.map((file) => generateThumbnail(file)));

where files is an array with strings (paths of the images to be converted), and generateThumbnail() is an async function returning another string (paths to the generated thumbnails), when the process is done. So the whole thing should convert the files and return an array of strings.

Awaiting for the return?

My first, very naive, attempt to fix the problem was... to use await inside the mapping:

return await files.map(async file => await generateThumbnail(file));

And it seemed to work properly from the results perspective since the thumbnails were generated and there was no memory error. But the map is not returning the array of strings, but an array of promises. Which is... come on, await shouldn't return a promise, after all :-((

Ok, ok, the real reason is that array.map should return promises — that's what async functions are returning by default. And await before the array.map is doing... nothing since it's not a promise it can wait, but an array.

About the missing error — just a bit of luck that the memory was enough this time, these promises shouldn't run sequentially.

Looping sequentially

What is going to wait for the wait operator is just a simple for loop:

const thumbFiles = [];
for (const file of files) {
  const thumbnail = await generateThumbnail(file);
  thumbFiles.push(thumbnail);
}
return thumbFiles;

Yes. that is not a one-liner and not so “modern”, but works perfectly. There are a lot of examples of the same logic using array.reduce, but the code above is simple enough so everybody can understand what is going on. So I'll stick to it.

HTH