https://github.com/jabez128/stream-handbook
在node中,流可以帮助我们将事情的重点分为几份,因为使用流可以帮助我们将实现接口的部分分割成一些连续的接口,这些接口都是可重用的。接着,你可以将一个流的输出口接到另一个流的输入口,然后使用使用一些库来对流实现高级别的控制。(metamask中就是这样,使用了很多流,希望这几天的学习能够让我真正搞懂metamask几个部分之间到底是怎么相互工作的)
为什么应该使用流
在node中,I/O都是异步的,所以在和硬盘以及网络的交互过程中会涉及到传递回调函数的过程。你之前可能会写出这样的代码:
var http = require('http');//node自带 var fs = require('fs'); var server = http.createServer(function (req, res) { fs.readFile(__dirname + '/data.txt', function (err, data) { res.end(data);//浏览器上显示 console.log(data);//终端上显示 }); }); server.listen(8000);
上面的这段代码并没有什么问题,但是在每次请求时,我们都会把整个data.txt文件读入到内存中,然后再把结果返回给客户端。想想看,如果data.txt文件非常大,在响应大量用户的并发请求时,程序可能会消耗大量的内存,这样很可能会造成用户连接缓慢的问题。
其次,上面的代码可能会造成很不好的用户体验,因为用户在接收到任何的内容之前首先需要等待程序将文件内容完全读入到内存中。
所幸的是,(req,res)参数都是流对象,这意味着我们可以使用一种更好的方法来实现上面的需求:
var http = require('http'); var fs = require('fs'); var server = http.createServer(function (req, res) { var stream = fs.createReadStream(__dirname + '/data.txt'); stream.pipe(res); console.log(stream); }); server.listen(8000);
console.log(stream)结果为:
ReadStream { _readableState: ReadableState { objectMode: false, highWaterMark: 65536, buffer: BufferList { length: 0 }, length: 0, pipes: ServerResponse { _events: [Object], _eventsCount: 5, _maxListeners: undefined, output: [], outputEncodings: [], outputCallbacks: [], outputSize: 0, writable: true, _last: false, chunkedEncoding: false, shouldKeepAlive: true, useChunkedEncodingByDefault: true, sendDate: true, _removedConnection: false, _removedContLen: false, _removedTE: false, _contentLength: null, _hasBody: true, _trailer: '', finished: false, _headerSent: false, socket: [Socket], connection: [Socket], _header: null, _onPendingData: [Function: bound updateOutgoingData], _sent100: false, _expect_continue: false, [Symbol(isCorked)]: false, [Symbol(outHeadersKey)]: null }, pipesCount: 1, flowing: true, ended: false, endEmitted: false, reading: false, sync: true, needReadable: false, emittedReadable: false, readableListening: false, resumeScheduled: true, emitClose: false, destroyed: false, defaultEncoding: 'utf8', awaitDrain: 0, readingMore: false, decoder: null, encoding: null }, readable: true, _events: { end: [ [Function], [Function] ], data: [Function: ondata] }, _eventsCount: 2, _maxListeners: undefined, path: '/Users/user/stream-learning/data.txt', fd: null, flags: 'r', mode: 438, start: undefined, end: Infinity, autoClose: true, pos: undefined, bytesRead: 0, closed: false }