pipe(Node.jsstream)和bl(BufferList)如何一起工作?

这实际上是Node.js教程([ https://github.com/workshopper/learnyounode][1] )的第8号练习。

目标:编写一个执行HTTP GET请求的程序作为第一个命令行参数提供给您的URL。 从服务器收集所有数据(不只是第一个“数据”事件),然后写两行到控制台(标准输出)。

你写的第一行应该是一个整数,表示从服务器接收的字符数。 第二行应包含服务器发送的完整string。

所以这是我的解决scheme (它通过,但看起来比官方的解决scheme丑)。

var http = require('http'), bl = require('bl'); var myBL = new bl(function(err, myBL){ console.log(myBL.length); console.log(myBL.toString()); }); var url = process.argv[2]; http.get(url, function(res){ res.pipe(myBL); res.on('end', function(){ myBL.end(); }); }); 

官方解决scheme:

 var http = require('http') var bl = require('bl') http.get(process.argv[2], function (response) { response.pipe(bl(function (err, data) { if (err) return console.error(err) data = data.toString() console.log(data.length) console.log(data) })) }) 

我很难理解官方解决scheme的工作原理。 我主要有两个问题:

  1. bl构造函数期望第二个参数是bl的一个实例(根据bl模块的文档,[ https://github.com/rvagg/bl#new-bufferlist-callback–buffer–buffer-array-] [2 ] ),但是数据是什么? 它从哪里来。 当它被传递来构造BL实例时,它应该是未定义的。

  2. 什么时候bl.end()被调用? 我可以看到没有bl.end()被称为…

希望有人能够对这些问题提出一些看法。 (我知道我应该阅读源代码,但你知道…)

  [1]: https://github.com/workshopper/learnyounode [2]: https://github.com/rvagg/bl#new-bufferlist-callback--buffer--buffer-array- 

这部分的blitub页面或多或less地回答你的问题:

在构造函数中给它一个callback,并像concat-stream一样使用它:

 const bl = require('bl') , fs = require('fs') fs.createReadStream('README.md') .pipe(bl(function (err, data) { // note 'new' isn't strictly required // `data` is a complete Buffer object containing the full data console.log(data.toString()) })) 

请注意,当您使用这种callback方法时,生成的数据参数是列表中所有Buffer对象的串联。 如果你想避免这种连接的开销(在极端的性能意识的情况下),那么避免callback方法,而只是倾听'结束',而不是像标准的stream。

你正在向bl传递一个callback函数,这基本上是一个函数,当它有一个数据stream来处理时,它会调用它。 因此,数据现在是未定义的…它只是一个参数名称,稍后将用于传递来自GET调用的文本进行打印。

我相信bl.end()没有被调用,因为没有真正的性能开销让它运行,但我可能是错的。

我已经阅读了bl库和节点streamAPI的源代码。

BufferList是一个自定义的双工stream,既可读readableStream.pipe(BufferList)写。当运行readableStream.pipe(BufferList) ,默认情况下,当源stream发出end()时,在BufferList上调用end()没有更多的数据可读。

请参阅BufferList.prorotype.end的实现 :

 BufferList.prototype.end = function (chunk) { DuplexStream.prototype.end.call(this, chunk) if (this._callback) { this._callback(null, this.slice()) this._callback = null } } 

因此,传递给BufferList的callback将在BufferListBufferList接收到所有数据后调用,调用此this.slice()将返回连接BufferList中所有缓冲区的结果,其中data参数来自哪里。

 var request=require('request') request(process.argv[2],function(err,response,body){ console.log(body.length); console.log(body); }) 

你可以看看这个方法来解决上面的练习,ps请求是第三方模块