朴(piáo)老湿的九浅一深 Node.js 貌似没有详细介绍 Stream 模块。本身对这个模块算是比较熟悉,顺手也 PO 上来备忘一下吧。html
若是说 Activity、Service、Content Provider 和 Broadcast Receiver 并称 Android 四大组件的话,那么 Node 的「N 大模块」里面一定要有 Stream。node
相似于 *nix 将几乎全部设备抽象为文件同样,Node 将几乎全部 IO 操做都抽象成了 Stream 的操做。Stream 是一个抽象的概念,总之就是会冒数据(以 Buffer 为单位),或者可以吸取数据的东西。git
在 Node 里读取一个文件的内容:github
var fs = require('fs') fs.readFile('/etc/hosts', function (err, buffer) { if (err) { return console.error(err.stack) } console.log(buffer.toString('utf8')) })
对于大文件操做,一口气所有读入内存确定是不行的,科学的作法是一份一份地读:api
var fs = require('fs') fs.open('/etc/hosts', 'r', function (err, fd) { if (err) { return console.error(err.stack) } // 内啥,我想演示一下用 fs.read 逐片逐片读文件的,但那玩意实在太烦, // 因此我懒得写了。本身看文档。 })
很烦对吧?每次读多少?这些每每不是咱们须要关心的,因而就有了 Stream。Node 对这种传统的读取过程隐藏到了文件读取 Stream 中:网络
var fs = require('fs') fs.createReadStream('/etc/hosts').pipe(process.stdout)
没错,就两行代码,将 hosts 文件的内容显示出来。dom
在 Node 的早期版本中,Stream 只是一个简单的继承自 EventEmitter 的类。以文件读取流为例子,一旦开始读取,数据就会源源不断地读出,触发 'data'
事件——嗯一开始的确是一个不错的设计,但若是你想等一下,好比说等待某个回调后再开始处理这些数据。。。好吧,每一片数据只会冒出来一次,没人消费的话它就没了;OK 你想到了用 pause-stream「暂停」一下这个流,等下再消费?完了,数据会暂存在内存中,慢慢堆积,而后,你懂了。ide
固然并非说原来不断冒 'data'
的读取方式是很差的,只是说它对于某些情景,好比文件读取,好比网络传输,没办法控制读取速度而已。网络传输注定是没办法控制读取速度的,人家给你多少你都得吃进去;但文件读取,能不能按须要,处理多少读多少呢?post
Node 0.10.X 就对 Stream 作了这样的改动:默认状况下,Node 会尽量使用「拉」模式,也就是说只有 pipe 链末端的流消费者真正须要数据的时候,数据才会从源头被取出,而后顺着管子一路到达消费者。ui
Stream 的精髓在于 .pipe()
嗯。
推荐一个牛逼哄哄的库:request,Stream API 运用到极致的 HTTP(S) 请求库。
var fs = require('fs') , request = require('request') var writer = fs.createWriteStream('hexie.pkg') // 'close' 和 'error' 事件分别是写入完成和发生错误,懒得写,看文档。 request('http://xxxxxxx.xxx/abs123.avi').pipe(writer)
fs.createWriteStream()
建立了一个新文件并返回了该文件的 Writable Stream;request()
发起了一个 HTTP 请求并返回一个 Readable Stream。将这两个 Stream 经过 .pipe()
一对接,request()
的下载流量就被直接导到本地文件并写入磁盘,神奇吧?
推荐一下朴老湿好基友苏千大神(@Python发烧友)的 formstream,配合 request 简直碉堡。
var request = require('request') , FormStream = require('formstream') var form = FormStream() .field('title', 'ni dong de') .file('attachment', 'hexie.pkg') var upload = request.post('http://xxxx.xxx/upload', { headers: form.headers() }, function (err, res, body) { // ... 略 }) form.pipe(upload)
最后,最后,还得感谢老雷(@雷宗民)的 Node.js API 翻译计划,俺就是翻译完 Stream 章节才理解上面这些精髓的。
以上。