JavaScript NodeJS 如何将流/承诺与异步函数一起使用?

Posted

技术标签:

【中文标题】JavaScript NodeJS 如何将流/承诺与异步函数一起使用?【英文标题】:JavaScript NodeJS How to use stream/promises with async functions? 【发布时间】:2021-11-16 04:16:42 【问题描述】:

我在 Node.js 中有一个 JS 异步函数。比如说,它从一个 URL 下载一个文件并用它做一些事情,例如。解压它。我是这样写的,它可以工作,但是eslint 向我展示了一股浓浓的代码味道:error Promise executor functions should not be async no-async-promise-executorAsync 是必需的,因为 await fetch 在 body 函数中。

我对@9​​87654326@ 和async/await 不够熟练,无法自行纠正。我想摆脱 Promise 并充分使用 async/await。模块stream/promises 似乎是从Node-15 开始的方式,正如这里how-to-use-es8-async-await-with-streams 所评论的那样。在这种情况下如何使用await pipeline(...)?也许有更好更短的方法?

函数如下:

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

【问题讨论】:

不确定这是否是您的问题,但async function doSomething 对您没有任何作用......它应该只是function doSomething,因为您返回Promise 嗯,是的,我从一些较大的代码中提取了该函数,但这确实是题外话。我正在从我的示例中删除它。 【参考方案1】:

您可以在 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';
  );

【讨论】:

您使用fetch(url).then 避免使用async (resolve, reject) =>...,但我的问题是仅在函数体中使用async/awaitawait fetch(url)?或者作为替代方案,如果可能的话,使用stream/promises pipeline 函数? 抱歉。我已经更新了我的答案。流对于您想要完成的简单事情来说有点多 谢谢!我不知道writeFile。代码更干净! pipelinecreateWriteStream 是否也可行,例如 pipeline( ~fetch as a stream~, fs.createWriteStream) 我正在使用命名导入 - import writeFile from 'fs/promises';。您也可以使用import fs from 'fs/promises';,并且您会以 Promise 的形式获得大部分文件系统 API。然后您可以等待大多数文件系统操作:await fs.writeFile(...);。此外,如果这解决了您的问题,接受答案是有礼貌的,这样其他人就知道它有效。干杯! 我当然会!谢谢!到目前为止仍在消化答案。【参考方案2】:

您可以在到达执行程序之前简单地执行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((reject, resolve) => 
    body.on('error', reject);
    body.on('finish', resolve);
  );
  
;

总的来说,我的建议是从你的承诺执行者中删除尽可能多的代码。在这种情况下,Promise 仅用于捕获解决/拒绝。

请注意,我还从doSomething 中删除了doWhatever - 这使得doSomething 更加健壮。你可以这样做:

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

最后我建议您将someFile 设置为doSomething 的参数,而不是从更广泛的上下文中引用它!

【讨论】:

谢谢。您的代码确实非常干净,并且与我可怜的代码相反。对不起someFile 发错地方了,写好sn-p的辛苦工作中的一个错误。【参考方案3】:

要使用您正在寻找的pipeline 函数,它会是

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

【讨论】:

以上是关于JavaScript NodeJS 如何将流/承诺与异步函数一起使用?的主要内容,如果未能解决你的问题,请参考以下文章

NodeJS 中的 Firebase javascript 承诺

如何承诺此功能-nodejs [重复]

如何使用 Bluebird 承诺 NodeJS Express

一个承诺的 mysql 模块将如何与 NodeJS 一起工作?

如何从 Azure 函数内部发出基于承诺的 HTTP 发布请求 (NodeJS)?

执行 .Then() 承诺 NodeJS