MST

星途 面试题库

面试题:Node.js 流的背压处理机制及应用场景

在 Node.js 流操作中,背压(Backpressure)是一个重要的概念。请详细解释背压产生的原因、Node.js 中处理背压的机制,并举出至少一个实际应用场景中需要处理背压的例子,并说明如何处理。
39.4万 热度难度
前端开发Node.js

知识考点

AI 面试

面试题答案

一键面试

背压产生的原因

在 Node.js 流操作中,背压通常产生于可读流(Readable Stream)产生数据的速度快于可写流(Writable Stream)消费数据的速度。例如,当一个可读流从文件系统快速读取数据,而对应的可写流是向网络套接字写入数据,由于网络传输速度相对较慢,可写流处理数据的速度跟不上可读流产生数据的速度,此时就会出现背压。

Node.js 中处理背压的机制

  1. pipe() 方法:Node.js 的 stream 模块中的 pipe() 方法会自动处理背压。当使用 readable.pipe(writable) 时,可读流会根据可写流的 highWaterMark(缓冲区水位标记)来暂停和恢复数据的读取。如果可写流的内部缓冲区已满(达到 highWaterMark),可读流会暂停读取数据,直到可写流处理完部分数据,触发 drain 事件,此时可读流再恢复读取。
  2. 手动处理:通过监听可读流的 data 事件和可写流的 drain 事件来手动处理背压。在 data 事件中,当写入可写流的数据返回 false 时,说明可写流缓冲区已满,此时需要暂停可读流;当可写流触发 drain 事件时,说明其缓冲区有空间了,可以恢复可读流。

实际应用场景及处理方式

场景:从文件读取大量数据并通过网络发送出去,比如文件上传功能。假设要将一个大文件上传到远程服务器。 处理方式

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

const server = http.createServer((req, res) => {
    const readableStream = fs.createReadStream('largeFile.txt');
    const writableStream = res;

    let paused = false;
    readableStream.on('data', (chunk) => {
        if (paused) {
            // 如果因为背压暂停了,将数据缓存到内部缓冲区
            return;
        }
        const writeResult = writableStream.write(chunk);
        if (!writeResult) {
            paused = true;
            readableStream.pause();
        }
    });

    writableStream.on('drain', () => {
        paused = false;
        readableStream.resume();
    });

    readableStream.on('end', () => {
        writableStream.end();
    });
});

server.listen(3000, () => {
    console.log('Server is running on port 3000');
});

在上述代码中,从文件读取数据(fs.createReadStream)作为可读流,HTTP 响应(res)作为可写流。通过监听 data 事件和 drain 事件来处理背压,确保文件数据能平稳地通过网络发送出去,不会因为网络传输速度慢导致内存溢出等问题。