MST

星途 面试题库

面试题:Node.js 流处理大文件时如何优雅处理背压问题

当使用 Node.js 的 Stream 进行大文件处理,特别是在可读流数据产生速度快于可写流消费速度的情况下,会出现背压问题。请详细描述你会采取哪些策略和方法来优雅地处理背压,确保数据不丢失且系统稳定运行,并给出相关代码示例。
30.5万 热度难度
前端开发Node.js

知识考点

AI 面试

面试题答案

一键面试

处理背压的策略和方法

  1. 监听 drain 事件

    • 当可写流缓冲区已满时,继续写入数据会返回 false。此时,我们可以监听可写流的 drain 事件,当缓冲区有空间时,drain 事件会触发,我们可以在这个时候继续写入数据。
  2. 使用 pause()resume() 方法

    • 可读流有 pause()resume() 方法。当可写流缓冲区满,返回 false 时,我们可以调用可读流的 pause() 方法暂停数据读取,当 drain 事件触发时,再调用 resume() 方法恢复读取。
  3. 使用 Transform 流作为中间缓冲

    • Transform 流可以在可读流和可写流之间起到缓冲作用,通过控制其内部缓冲区大小来处理背压。

代码示例

const fs = require('fs');
const readableStream = fs.createReadStream('largeFile.txt');
const writableStream = fs.createWriteStream('outputFile.txt');

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();
});

在上述代码中:

  1. 当从可读流 readableStream 读取到数据时,尝试写入可写流 writableStream
  2. 如果 write 方法返回 false,说明可写流缓冲区已满,暂停可读流,并设置 paused 标志。
  3. 当可写流触发 drain 事件时,说明缓冲区有空间了,恢复可读流读取,并清除 paused 标志。
  4. 当可读流结束时,结束可写流。