Node Stream handbook 笔记

来源:互联网 发布:js中数组添加元素 编辑:程序博客网 时间:2024/05/17 21:50

Node Stream handbook 笔记


什么是stream

这里这么理解:数据流是水,而对数据的处理工具是管道,水从管道入口流进,经过管道的处理,从出口流出,多个管道可以串联起来。

如果不用流,我们的代码可能是这样的:
```
var server = http.createServer(function (req, res) {
    fs.readFile(__dirname + '/data.txt', function (err, data) {
        res.end(data);
    });
});
```
这里有一个重要问题就是,只有把整个 `data.txt` 文件内容全部读入内存之后才会触发回调,对于大文件,很可能是无法完整读入内存的,即便是不大的文件,这也是对内存的浪费。

那么用 stream 之后我们可以这样写:
```
var stream = fs.createReadStream(__dirname + '/data.txt');
    stream.pipe(res);
```
这样不仅没有回调的嵌套,而且 `pipe` 函数会自动处理 `data` 和 `end` 事件,这里不会把 `data.txt` 文件整个读入内存,而是每当读取一个数据片段的时候就会自动 `pipe` 给 `res` 对象进行处理。
事实上 `pipe` 方法不但能分段处理数据流,而且他还可以自动调节性能。

这样如果我们需要压缩数据就很简单,我们只需要再接一根管子就行了:

```
var stream = fs.createReadStream(__dirname + '/data.txt');
    stream.pipe(oppressor(req)).pipe(res);
```

使用stream处理数据的时候,我们可以灵活的把不同的水管连接起来以达到自己的目的。
## Stream 常见类型
常见的是:Readable,Writable,Transform

pipe

任何一种流,都会用 `pipe` 方法来实现输入和输出。

```
src.pipe(dest)
```

Readable

Readable 可以产生数据流:
```
readable.pipe(dest)
```
我们可以通过 `push` 方法向一个 `Readable` 流中添加数据:

```
var Readable = require('stream').Readable;

var rs = new Readable;
rs.push('beep ');
rs.push('boop\n');
rs.push(null);

rs.pipe(process.stdout);
```
根据流的思想,我们不应该是一下把数据全部塞进去才开始读,应该是一边塞数据,一遍可以读。
我们可以通过添加一个 `_read` 方法来向 `Readable` 中推送数据。
```
var Readable = require('stream').Readable;
var rs = Readable();

var c = 97;
rs._read = function () {
    rs.push(String.fromCharCode(c++));
    if (c > 'z'.charCodeAt(0)) rs.push(null);
};

rs.pipe(process.stdout);
```

除了将 readable直接pipe到另一个流中,我们也可以自己读取数据:
```
var Readable = require('stream').Readable;
var rs = Readable();

var c = 97;
rs._read = function () {
    rs.push(String.fromCharCode(c++));
    if (c > 'z'.charCodeAt(0)) rs.push(null);
};

rs.on('readable', function () {
  var buf = rs.read();
  console.log(buf.toString());
});
```

当 `readable` 流准备好数据之后,会触发 `readable` 事件,监听此事件就可以。

如果我们一次读的数据太多,希望塞回去一点怎么办,我们可以用 `unshift`。比如我们希望一次处理一个单词:
```
var Readable = require('stream').Readable;
var rs = new Readable();

rs.push("dog boy girl cat");
rs.push(null);

rs.on('readable', function () {
  var buf = rs.read();
  console.log("hello:" + buf.toString());
});
```
结果一下全部处理完了。
那么我们可以用unshift来塞回去:
```
var Readable = require('stream').Readable;
var rs = new Readable();

rs.push("dog boy girl cat");
rs.push(null);

rs.on('readable', function () {
  var buf = rs.read(),
      offset = 0;
  for (; offset < buf.length; offset++) {
    if (buf[offset].toString() == "32") {
      console.log("hello:" + buf.slice(0, offset));
      break;
    }
  }
  rs.unshift(buf.slice(offset));
});
```
事实证明上面这样写是塞不回去的。。。为毛。。。

Writable


Writable 是一个只进不出的流:
```
src.pipe(writableStream);
```
对 writable 流,只需要定义一个 `_write` 方法,就可以将一个 readable 流导入其中。我们借用上面的 `readable` 流,把它的结果导入 `writable` 流总

```
var Readable = require('stream').Readable;
var rs = Readable();

var c = 97;
rs._read = function () {
    rs.push(String.fromCharCode(c++));
    if (c > 'z'.charCodeAt(0)) rs.push(null);
};

var Writable = require('stream').Writable;
var ws = Writable();
ws._write = function (chunk, enc, next) {
  console.log(chunk.toString());
  next();
};
rs.pipe(ws);
```

我们可以通过调用 `write` 方法向里面写入内容
```
ws.write('beep ');

setTimeout(function () {
    ws.end('boop\n');
}, 1000);
```

Transform

0 0
原创粉丝点击