Search code examples
javascriptnode.jsasync-awaites6-promise

JavaScript NodeJS How to use stream/promises with async functions?


I have a JS async function in Node. Say, it downloads a file from a URL and does something with it, eg. unzip it. I wrote it like this, it works, but eslint showed me there is a thick code smell: error Promise executor functions should not be async no-async-promise-executor. Async was required because of await fetch in body function.

I am not skilled enough with streams nor async/await to correct it by myself. I would like to get rid of the Promise and fully use async/await. The module stream/promises seems the way to go from Node-15 on as commented here how-to-use-es8-async-await-with-streams. How to use await pipeline(...) in this context? Maybe there's a better and shorter way?

Here's the function:

function doSomething(url) {
  return new Promise(async (resolve, reject) => {
    try {
      const fileWriteStream = fs.createWriteStream(someFile, {
        autoClose: true,
        flags: 'w',
      });

      const res = await fetch(url);
      const body = res.body;
      body
        .pipe(fileWriteStream)
        .on('error', (err) => {
          reject(err);
        })
        .on('finish', async () => {
          await doWhatever();
          resolve('DONE');
        });
    } catch (err) {
      reject(err);
    }
  });
}

Solution

  • You can use the fs/promises in NodeJS and trim your code down to the following:

    import { writeFile } from 'fs/promises'
    
    async function doSomething(url) {
        const res = await fetch(url);
        if (!res.ok) throw new Error('Response not ok');
        await writeFile(someFile, res.body, { encoding: 'utf-8'})
        await doWhatever();
        return 'DONE';
      });
    }