Node.JS

从Stream 1到Stream 3的流API比较

 Node Stream流模块是用来处理数据流的强大模块,流API不断在改进,Stream 1引入了推流push-stream允许开发者有效地使用数据,Stream 2在推流基础上加入拉流pull-stream,这两种风格不能一起使用,Stream 3以一种灵活的方式解决了这个问题,允许同样的流既能push推又能拉pull,Stream3将在Node v0.11/v0.12和io.js中适用。

Stream 1推流

 在最初的流实现中,每次当有数据可用时,都有一个数据事件发生,开发者可以使用pause()和resume()来控制流,调用pause()将引起底层停止发送数据事件的发生。

// node 0.8
 
var fs = require('fs');
var stream = fs.createReadStream('readme.txt');
stream.setEncoding('utf8');
stream.pause();
 
// 一秒后再开始流Resume the stream in 1 second
setTimeout(stream.resume.bind(stream), 1000);
 
var data = '';
stream.on('data', function(chunk) {
  data += chunk;
})
 
stream.on('end', function() {
  // 流终点到达 End of the stream has been reached and no more data can be read
  console.log('Data length: %d', data.length);
});
 
> node test.js
Data length: 1506

 不管怎样,Stream 1有一些问题:

  • 暂停pause() 方法并不暂停,它只是建议advisory-only.
  • 无论你是否准备好,'数据' 事件就立即来了
  • 没有办法消费使用指定数量的字节,然后将剩余的交给程序其他部分来处理。

 

Stream 2拉流

 Node 0.10引入了Streams 2 API,增加了Pull拉方式,也就是从数据流读取时可以采取拉方式,这样解决了以前的问题,流总是从暂停状态开始,通过read(numBytes) API读取,此外,当数据可用时,一个可读的事件将被发射。

// node 0.10 - pull stream, readable event example
 
var fs = require('fs');
var stream = fs.createReadStream('readme.txt');
stream.setEncoding('utf8');
 
//不需要使用stream.pause();暂停流
 
var data = '';
stream.on('readable', function() {
  var chunk;
  while(chunk = stream.read()) {
    data += chunk;
  }
});
 
stream.on('end', function() {
  //流终点到达 End of the stream has been reached and no more data can be read
  console.log('Data length: %d', data.length);
});
 
> node test.js
Data length: 1506

 原来Stream 1读数据的推模型还是可以使用,能够使用一个数据事件处理器来实现,增加一个数据事件处理器在un-pausing时有副作用。

// node 0.10 - push stream, data event example
 
var fs = require('fs');
var stream = fs.createReadStream('readme.txt');
stream.setEncoding('utf8');
stream.pause();
 
//一秒后重新开始流 Resume the stream in 1 second
setTimeout(stream.resume.bind(stream), 1000);
 
var data = '';
stream.on('data', function(chunk) {
  data += chunk;
})
 
stream.on('end', function() {
  // End of the stream has been reached and no more data can be read
  console.log('Data length: %d', data.length);
});
 
> node test.js
Data length: 1506

 但是拉Pull和Push推不能混合在一起使用

 

Stream 3混合流

 在io.js的1.0.1中,我们有一个混合流的实现,缺省默认流还是可以被暂停,增加数据事件处理器还是可以auto-unpause自动取消暂停流,如果我们暂停流,然后使用read()方法,它将发射一个相应的数据事件。

// node 0.11+, io.js 1.0.1
 
var fs = require('fs');
var stream = fs.createReadStream('readme.txt');
stream.setEncoding('utf8');
stream.pause();
 
var pulledData = '';
var pushedData = '';
 
stream.on('readable', function() {
  var chunk;
  while(chunk = stream.read()) {
    pulledData += chunk;
  }
});
 
stream.on('data', function(chunk) {
  pushedData += chunk;
});
 
stream.on('end', function() {
  // End of the stream has been reached and no more data can be read
  console.log('Pulled data length: %d', pulledData.length);
  console.log('Pushed data length: %d', pushedData.length);
});
 
> node test.js
Pulled data length: 1506
Pushed data length: 1506

支持ES6的IO.js 1.0.0发布