乐趣区

关于前端:从Readable-steam可读流中读取数据的方式

可读流是对数据源的形象,从 Readable 中读取数据的模式有两种,non-flowing(非流动模式也称为 paused)模式和 flowing(流动)模式。

非流动模式

  • 在非流动模式下,当流中有可读取的数据时,会触发 readable 事件,所以该事件被触发时须要重复调用流的 read 办法从缓存中获取最新的数据直到 read 办法返回 null,示意没有数据可读,新建的可读流默认处于该模式下。罕用形式如下:
const stream = fs.createReadStream(path.resolve(__dirname, './xxx.js'));
stream.on('readable', () => {
  let chunk;
  while (null !== (chunk = stream.read())) {console.log('chunk:' + chunk.toString());
  }
});
  • 在没有指定编码方式的前提下,read 办法返回的是 Buffer,能够调用 setEncoding 办法指定数据的编码,这样调用 read 办法时就能够间接获取到 string。提前指定 encoding 的益处是对于多字节字符流会确保多个字节不会被宰割到不同的 chunk 中:
const stream = fs.createReadStream(path.resolve(__dirname, './print.js'), {encoding: 'utf8'});
stream.on('readable', () => {
  let chunk;
  while (null !== (chunk = stream.read())) {console.log('chunk:' + chunk);
  }
});
  • 在非流动模式下调用 Readable.resume()或者通过 pipe 连贯到一个 Writable,可切换到流动模式,如果此时没有注册 data 事件处理函数,那么产生的新数据回失落。

流动模式

  • 能够通过注册 data 事件处理函数让可读流切换到流动模式,在该模式下当数据源中有新的数据准备就绪时,新的数据会被传递给 data 事件的处理函数,能够在函数中解决新的数据。如通过以下形式读取文件的内容:
const stream = fs.createReadStream(path.resolve(__dirname, './print.js'), {encoding: 'utf8'});
let chunks = '';
stream.on('data', (chunk) => {chunks += chunk;});

stream.on('end', () => {console.log(chunks);
});
  • 在流动模式下,能够通过两种形式切换回 pause 模式:

    1. 调用 pause 办法;
    2. 当可读流通过 pipe 管道连贯到其余流是,调用 unpipe 也会使流切换到 pause 模式;
  • 在流动模式下注册 readable 事件处理函数会让流进行流动,须要通过 read 读取数据;如果 readable 处理函数被移除,如果存在 data 处理函数,流会再次进入 flowing 模式;

异步迭代器

新版本的 node<v11.14.0> 中的 Readable 实现了异步迭代器,能够更加不便的读取数据:

const stream = fs.createReadStream(path.resolve(__dirname, './print.js'), {encoding: 'utf8'});

async function getData(stream) {
  let chunks = '';
  for await (let chunk of stream) {chunks += chunk;}
  return chunks;
}

getData(stream).then(data => console.log(data));

如果循环通过 break, return, throw 终止,流会被销毁。每次读取的 chunk 的大小等于流的 highWaterMark 选项,没有指导该选项的状况下,默认值为 64kb,因而如果文件的大小小于该值,文件的内容会在单个 chunk 中被返回。

补充

流中的数据也有两种模式,二进制模式和对象模式。二进制模式下读取的数据类型为 Buffer 或者 String,后面的例子都是在二进制模式下读取数据。而对象模式下能够返回任意的 javascript 的对象,上面举一个简略的例子, Readable.from()创立的流默认是 objectMode:

const stream = Readable.from([{name: 'Bob',}, {name: 'Jenny'}, {name: 'Lili'}]);

async function getData(stream) {for await (let chunk of stream) {console.log(chunk);
  }
}

getData(stream);

输入如下:

{name: 'Bob'}
{name: 'Jenny'}
{name: 'Lili'}
退出移动版