【问题标题】:JavaScript NodeJS How to use stream/promises with async functions?JavaScript NodeJS 如何将流/承诺与异步函数一起使用?
【发布时间】: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
  • 嗯,是的,我从一些较大的代码中提取了该函数,但这确实是题外话。我正在从我的示例中删除它。

标签: javascript node.js async-await es6-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';
}

【讨论】:

    猜你喜欢
    • 2018-08-26
    • 2018-09-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-03
    • 2019-06-21
    • 2018-10-17
    • 2018-06-13
    相关资源
    最近更新 更多