简体   繁体   English

JavaScript NodeJS 如何在异步函数中使用流/承诺?

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

I have a JS async function in Node.我在 Node 中有一个 JS 异步 function。 Say, it downloads a file from a URL and does something with it, eg.比如说,它从 URL 下载一个文件并用它做一些事情,例如。 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 .我是这样写的,它可以工作,但是eslint告诉我有一股浓浓的代码味道: error Promise executor functions should not be async no-async-promise-executor Async was required because of await fetch in body function.由于正文 function 中的await fetch ,因此需要Async

I am not skilled enough with streams nor async/await to correct it by myself.我对流不够熟练,也没有async/await streams自己纠正它。 I would like to get rid of the Promise and fully use async/await .我想摆脱 Promise 并完全使用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 .模块stream/promises似乎是从 Node-15 到 go 的方式,如此处how-to-use-es8-async-await-with-streams所评论。 How to use await pipeline(...) in this context?如何在这种情况下使用await pipeline(...) Maybe there's a better and shorter way?也许有更好更短的方法?

Here's the function:这是 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);
    }
  });
}

You could simply perform the await before getting to the executor:您可以在到达执行程序之前简单地执行await

async function doSomething(url) {
  
  const fileWriteStream = fs.createWriteStream(someFile, { autoClose: true, flags: 'w' });
  
  let { body } = await fetch(url);
  
  body.pipe(fileWriteStream);
  
  return new Promise((resolve, reject) => {
    body.on('error', reject);
    body.on('finish', resolve);
  });
  
};

My advice in general is to remove as much code from within your promise executors as possible.我的一般建议是尽可能多地从 promise 执行程序中删除代码。 In this case the Promise is only necessary to capture resolution/rejection.在这种情况下,Promise 只需要捕获分辨率/拒绝。

Note that I've also removed doWhatever from within doSomething - this makes doSomething much more robust.请注意,我还从doSomething中删除doWhatever - 这使得doSomething更加健壮。 You can simply do:你可以简单地做:

doSomething('http://example.com').then(doWhatever);

Lastly I recommend you set someFile as a parameter of doSomething instead of referencing it from some broader context!最后,我建议您将someFile设置为doSomething的参数,而不是从更广泛的上下文中引用它!

To use the pipeline function you're looking for, it would be要使用您正在寻找的pipeline function,它将是

const { pipeline } = require('stream/promises');

async function doSomething(url) {
  const fileWriteStream = fs.createWriteStream(someFile, {
    autoClose: true,
    flags: 'w',
  });

  const res = await fetch(url);
  await pipeline(res.body, fileWriteStream);
  await doWhatever();
  return 'DONE';
}

You can use the fs/promises in NodeJS and trim your code down to the following:您可以在 NodeJS 中使用fs/promises并将您的代码缩减为以下内容:

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';
  });
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM