前言
之前基于流处理构建工具gulp介绍,现在对stream模块进行简要分析,以便更好的使用构建工具,以及进行插件开发。
Stream
Stream
模块有四个类,Readable
, Writable
, Duplex
, Transform
,Transform
可以看做自成体系的子类。从使用角度来说,模块定义的类都为基类,是不具备直接使用条件的,需要程序实现相关接口方可使用。
Stream.Readable
此类需要实现_read
接口,用通俗的话来讲,可读流相当于发货仓库,仓库中的货物储备交由_read
处理,具体发货模块内部自行处理。可读流对象有flowing mode
,non-flowing mode
两种模式,前者自动处理发货,后者需要手动控制发货。
javascript
// inherit stream.Readable function Love() { stream.Readable.call(this); this._max = 5; this._index = 0; } util.inherits(Love, stream.Readable); Love.prototype._read = function() { var i = this._index++; if (i > this._max) { this.push('beautiful'); this.push(null); } else { var str = '' + i; var buf = new Buffer(str, 'utf8'); this.push(buf); } };
在初始化时,会自动调用_read
方法,利用ctx.push
方法写入内容到内部存储buffer
(进货)。代码很简单,传输的内容为0-5
,以及单词beautiful
。现在仓库中已经有货物,然后处理发货流程。
在flowing mode
下,监听data
事件即可,non-flowing mode
下,使用readable.read
方法获取内容,两种方式实际效果等同。此处readable
事件触发比较不解,暂时无法深入。
javascript
// flowing mode title.on('data', function(data) { writer.write(data); }); // non-flowing mode title.on('readable', function() { var chunk; while (null !== (chunk = title.read())) { writer.write(chunk); } });
至此,可以简单理解可读流就是进货出货的方式,定义接口实现进货,数据读取实现出货。
stream.Writable
此类需要实现_write
接口,用通俗的话来讲,可写流就是快递签收的过程。卖家不断发货,买家不断收货,签收的流程就是由_write
接口定义。
javascript
// inherit stream.Writable function Story() { stream.Writable.call(this); this._storage = new Buffer(''); } util.inherits(Story, stream.Writable); Story.prototype._write = function(chunk, encoding, callback) { this._storage = Buffer.concat([this._storage, chunk]); callback(); };
此处定义方式很简单,收到数据后,将数据保存在this._storage
私有变量中,这样就定义好可写流。下面来看如何综合使用两个类。
javascript
var reader = new Love(); var writer = new Story(); reader.on('readable', function() { var chunk; while (null !== (chunk = title.read())) { writer.write(chunk); } }); reader.on('end', function() { writer.end(); }); writer.on('finish', function() { fs.writeFileSync('./output.txt', this._storage); });
此处使用,将可读流传下来的数据全部写入output.txt
文件之中,非常简单的示例。
stream.Duplex
可读可写流,兼而有之两者特性,不清楚是否可以同时兼任两者,本人暂时未找到处理方案。
stream.Transform
能够同时兼任可读流与可写流,gulp
插件总结来说,就是自定义的stream.Transform
流。需要实现接口_transform
,_flush
,两者都可以_read
的特点,可以向后传递数据。
javascript
function Knight() { stream.Transform.call(this); } util.inherits(Knight, stream.Transform); Knight.prototype._transform = function(chunk, encoding, callback) { this.push(chunk); callback(); }; Knight.prototype._flush = function(callback) { this.push('dark knight'); callback(); };
示例非常简单,在内容后面再加上dark knight
字符串,不再赘述。
总结
对所有流来说,通常使用pipe
方法更为简便直接,所以应避免使用其他方式。完整代码地址:http://snowykiss.qiniudn.com/stream.js。
联系方式
QQ: 491229492
https://github.com/bornkiller