一篇文章构建你的 NodeJS 知识体系【上】-七、流

时间:2024-10-30 13:25:32

理解流

流是基于事件的 API,用于管理和处理数据。

  • 流是能够读写的
  • 是基于事件实现的一个实例

理解流的最好方式就是想象一下没有流的时候怎么处理数据:

  • fs.readFileSync 同步读取文件,程序会阻塞,所有数据被读到内存
  • fs.readFile 阻止程序阻塞,但仍会将文件所有数据读取到内存中
  • 希望少内存读取大文件,读取一个数据块到内存处理完再去索取更多的数据

流的类型

  • 内置:许多核心模块都实现了流接口,如 fs.createReadStream
  • HTTP:处理网络技术的流
  • 解释器:第三方模块 XML、JSON 解释器
  • 浏览器:Node 流可以被拓展使用在浏览器
  • Audio:流接口的声音模块
  • RPC(远程调用):通过网络发送流是进程间通信的有效方式
  • 测试:使用流的测试库

使用内建流 API

静态 web 服务器
想要通过网络高效且支持大文件的发送一个文件到一个客户端。

不使用流

const http = require('http');
const fs = require('fs');

http.createServer((req, res) => {
   
  fs.readFile(`${
     __dirname}/index.html`, (err, data) => {
   
    if (err) {
   
      res.statusCode = 500;
      res.end(String(err));
      return;
    }

    res.end(data);
  });
}).listen(8000);

使用流

const http = require('http');
const fs = require('fs');

http.createServer((req, res) => {
   
  fs.createReadStream(`${
     __dirname}/index.html`).pipe(res);
}).listen(8000);
  • 更少代码,更加高效
  • 提供一个缓冲区发送到客户端

使用流 + gzip

const http = require('http');
const fs = require('fs');
const zlib = require('zlib');

http.createServer((req, res) => {
   
  res.writeHead(200, {
   
    'content-encoding': 'gzip',
  });
  fs.createReadStream(`${
     __dirname}/index.html`)
    .pipe(zlib.createGzip())
    .pipe(res);
}).listen(8000);

流的错误处理

const fs = require('fs');
const stream = fs.createReadStream('not-found');

stream.on('error', (err) => {
   
  console.trace();
  console.error('Stack:', err.stack);
  console.error('The error raised was:', err);
});

使用流基类

可读流 - JSON 行解析器

可读流被用来为 I/O 源提供灵活的 API,也可以被用作解析器:

  • 继承自 steam.Readable 类
  • 并实现一个 _read(size) 方法
json-lines.txt
{
    "position": 0, "letter": "a" }
{
    "position": 1, "letter": "b" }
{
    "position": 2, "letter": "c" }
{
    "position": 3, "letter": "d" }
{
    "position": 4, "letter": "e" }
{
    "position": 5, "letter": "f" }
{
    "position": 6, "letter": "g" }
{
    "position": 7, "letter": "h" }
{
    "position": 8, "letter": "i" }
{
    "position": 9, "letter": "j" }

JSONLineReader.js

const stream = require('stream');
const fs = require('fs')