NodeJs IO流

是什么?

把一个东西从 A 搬到 B 该怎么搬呢?

抬起来,移动到目的地,放下不就行了么。

那如果这个东西有一吨重呢?

那就一部分一部分的搬。

其实 IO 也就是搬东西,包括网络的 IO、文件的 IO,如果数据量少,那么直接传送全部内容就行了,但如果内容特别多,一次性加载到内存会崩溃,而且速度也慢,这时候就可以一部分一部分的处理,这就是流的思想。

nodejs 四种流

可写流,可读流,双工流,转换流, 下文只描述了 可写流和可读流 的使用。

流的直观感受

从一个地方流到另一个地方,显然有流出的一方和流入的一方,流出的一方就是可读流(readable),而流入的一方就是可写流(writable)。

背压

但是 read 和 write 都是异步的,如果两者速率不一致呢?

如果 Readable 读入数据的速率大于 Writable 写入速度的速率,这样就会积累一些数据在缓冲区,如果缓冲的数据过多,就会爆掉,会丢失数据。

而如果 Readable 读入数据的速率小于 Writable 写入速度的速率呢?那没关系,最多就是中间有段空闲时期。

这种读入速率大于写入速率的现象叫做"背压",或者"负压"。也很好理解,写入段压力比较大,写不进去了,会爆缓冲区,导致数据丢失。

如何解决

当调用 writable stream 的 write 方法的时候会返回一个 boolean 值代表是写入了目标还是放在了缓冲区:

  • true: 数据已经写入目标
  • false:目标不可写入,暂时放在缓冲区

我们可以判断返回 false 的时候就 pause,然后等缓冲区清空了就 resume:

js 复制代码
const rs = fs.createReadStream(srcFilename);
const ws = fs.createWriteStream(dstFilename);

rs.on('data', function (chunk) {
    if (ws.write(chunk) === false) {
        rs.pause();
    }
});

rs.on('end', function () {
    ws.end();
});

ws.on('drain', function () {
    rs.resume();
});

这样就能达到根据写入速率暂停和恢复读入速率的功能,解决了背压问题。

drain钩子官方解析

Event: 'drain'#

Added in: v0.9.4

If a call to stream.write(chunk) returns false, the 'drain' event will be emitted when it is appropriate to resume writing data to the stream.

也可以用pipe 管道

ini 复制代码
const rs = fs.createReadStream(src);
const ws = fs.createWriteStream(dst);

rs.pipe(ws);

参考链接

神说要有光-# 彻底掌握 Node.js 四大流,解决爆缓冲区的"背压"问题

相关推荐
苏三说技术31 分钟前
推荐一个牛逼的RAG+KAG双引擎AI项目
后端
从此以后自律1 小时前
Spring 全家桶
java·后端·spring
utmhikari2 小时前
【日常随笔】深入回答纯Vibe Coding写后端项目的几个问题
后端·ai编程·vibecoding
尚早立志2 小时前
Spring Boot 源码研读之ConfigurableEnvironment 环境准备
java·spring boot·后端
布朗克1683 小时前
Go 入门到精通-08-复合类型之数组与切片
开发语言·后端·golang·数组与切片
fliter3 小时前
从手写 HTTP/1.1 到拆开 HTTP/2
后端
CaffeinePro3 小时前
FastAPI自动接口文档定制与美化、权限管控
后端·fastapi
AI人工智能+电脑小能手3 小时前
【大白话说Java面试题 第151题】【06_Spring篇】第11题:说一下 Spring Bean 的生命周期?
java·开发语言·后端·spring·面试
赫媒派5 小时前
Gin 12年零破坏API,架构哲学如何练成?
后端·go·gin
fliter6 小时前
Arborium:把 tree-sitter 语法高亮打包成 Rust 文档生态的基础设施
后端