Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/three.js/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 如何在流中使用ES8 async/await?_Javascript_Node.js_Async Await_Ecmascript 2017 - Fatal编程技术网

Javascript 如何在流中使用ES8 async/await?

Javascript 如何在流中使用ES8 async/await?,javascript,node.js,async-await,ecmascript-2017,Javascript,Node.js,Async Await,Ecmascript 2017,中的示例说明了如何使用内置的加密库和流计算文件的md5 var fs = require('fs'); var crypto = require('crypto'); // the file you want to get the hash var fd = fs.createReadStream('/some/file/name.txt'); var hash = crypto.createHash('sha1'); hash.setEncoding('hex'); fd.on('

中的示例说明了如何使用内置的加密库和流计算文件的md5

var fs = require('fs');
var crypto = require('crypto');

// the file you want to get the hash    
var fd = fs.createReadStream('/some/file/name.txt');
var hash = crypto.createHash('sha1');
hash.setEncoding('hex');

fd.on('end', function() {
    hash.end();
    console.log(hash.read()); // the desired sha1sum
});

// read all file and pipe it (write it) to the hash object
fd.pipe(hash);

但是,是否可以将其转换为使用ES8 async/await,而不是使用如上所示的回调,但同时仍保持使用流的效率?

async
/
await
仅适用于承诺,而不适用于流。有一些想法是创建一个额外的类似流的数据类型,它将获得自己的语法,但这些想法是高度实验性的,如果有的话,我将不详细介绍

无论如何,您的回调只等待流的结束,这非常适合于承诺。您只需包装流:

var fd = fs.createReadStream('/some/file/name.txt');
var hash = crypto.createHash('sha1');
hash.setEncoding('hex');
// read all file and pipe it (write it) to the hash object
fd.pipe(hash);

var end = new Promise(function(resolve, reject) {
    hash.on('end', () => resolve(hash.read()));
    fd.on('error', reject); // or something like that. might need to close `hash`
});
现在你可以等待这个承诺了:

(async function() {
    let sha1sum = await end;
    console.log(sha1sum);
}());

如果您使用的是节点版本>=v10.0.0,则可以使用和


类似这样的工作原理:

for (var res of fetchResponses){ //node-fetch package responses
    const dest = fs.createWriteStream(filePath,{flags:'a'});
    totalBytes += Number(res.headers.get('content-length'));
    await new Promise((resolve, reject) => {
        res.body.pipe(dest);
        res.body.on("error", (err) => {
            reject(err);
        });
        dest.on("finish", function() {
            resolve();
        });
    });         
}

节点V15现在有一个promisfiy管道。 这是最干净、最正式的方式

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

async function run() {
  await pipeline(
    fs.createReadStream('archive.tar'),
    zlib.createGzip(),
    fs.createWriteStream('archive.tar.gz')
  );
  console.log('Pipeline succeeded.');
}

run().catch(console.error);
我们都应该感谢它在这里所做的大量工作:

  • 捕获所有流中的错误
  • 引发错误时销毁未完成的流
  • 仅当最后一个可写流完成时返回

这个管道是Node.JS最强大的功能之一。使其完全异步并不容易。现在我们有了它。

我会发表评论,但没有足够的声誉

请注意: 如果您有一个正在传递流并执行异步/等待的应用程序,请务必在等待之前连接所有管道。您可能最终得到的流不包含您认为它们所做的事情。这是一个最小的例子

const { PassThrough } = require('stream');

async function main() {
    const initialStream = new PassThrough();

    const otherStream = new PassThrough();
    const data = [];
    otherStream.on('data', dat => data.push(dat));
    const resultOtherStreamPromise = new Promise(resolve => otherStream.on('end', () => { resolve(Buffer.concat(data)) }));

    const yetAnotherStream = new PassThrough();
    const data2 = [];
    yetAnotherStream.on('data', dat => data2.push(dat));
    const resultYetAnotherStreamPromise = new Promise(resolve => yetAnotherStream.on('end', () => { resolve(Buffer.concat(data2)) }));

    initialStream.pipe(otherStream);
    initialStream.write('some ');

    await Promise.resolve(); // Completely unrelated await

    initialStream.pipe(yetAnotherStream);
    initialStream.end('data');
    const [resultOtherStream, resultYetAnotherStream] = await Promise.all([
        resultOtherStreamPromise,
        resultYetAnotherStreamPromise,
    ]);

    console.log('other stream:', resultOtherStream.toString()); // other stream: some data
    console.log('yet another stream:', resultYetAnotherStream.toString()); // yet another stream: data
}
main();

async/await
只不过是对承诺的语法级支持。如果你能把这段代码放在一个承诺中,那么你就完成了。Node.js 10.x支持使用
来等待
来读取流(),但我认为这不是你这里的问题的正确概念。把它作为一个便条留给那些可能会遇到这种情况的人。祝贺你!现在这不是一个正确的答案,现在您可以对流使用异步循环。不幸的是,它现在是一个实验性功能。@MiF那么你的意思是答案是错误的,因为它不是“高度实验性”的,只是“实验性的”?:-DJ开始在所有异步情况下使用承诺和异步/等待。太奇怪了,这部小说没有在生产中发行。我认为,它现在是一个很好的sintacsys,不会改变。为什么要等待ReadStream结束呢?在散列函数有机会对数据执行之前,承诺不会解决吗?或者,至少,它不会创造一个比赛条件吗?我假设您希望将
fd.pipe(hash)
的值存储在一个变量中,并侦听
finish
事件,因为这将表示WriteableStream(hashing)已完成。@adam beck听起来您是对的。我为什么这样做?因为OP在他们的问题中也这么做了。请随意提出编辑建议。是否也应该在某个地方叫unpipe?我不得不挖掘几个小时,直到找到这个答案。例如,为什么节点流文档中没有包含此内容?但文档中有此内容。这是一个更好的回答你是一个救命稻草解释,我用这个承诺包装了一个https请求,我正在使用内置https模块的NodeJS。非常感谢。
const { PassThrough } = require('stream');

async function main() {
    const initialStream = new PassThrough();

    const otherStream = new PassThrough();
    const data = [];
    otherStream.on('data', dat => data.push(dat));
    const resultOtherStreamPromise = new Promise(resolve => otherStream.on('end', () => { resolve(Buffer.concat(data)) }));

    const yetAnotherStream = new PassThrough();
    const data2 = [];
    yetAnotherStream.on('data', dat => data2.push(dat));
    const resultYetAnotherStreamPromise = new Promise(resolve => yetAnotherStream.on('end', () => { resolve(Buffer.concat(data2)) }));

    initialStream.pipe(otherStream);
    initialStream.write('some ');

    await Promise.resolve(); // Completely unrelated await

    initialStream.pipe(yetAnotherStream);
    initialStream.end('data');
    const [resultOtherStream, resultYetAnotherStream] = await Promise.all([
        resultOtherStreamPromise,
        resultYetAnotherStreamPromise,
    ]);

    console.log('other stream:', resultOtherStream.toString()); // other stream: some data
    console.log('yet another stream:', resultYetAnotherStream.toString()); // yet another stream: data
}
main();