写点什么

Node.js 流基础:高效处理 I/O 操作的核心技术

作者:qife
  • 2025-08-09
    福建
  • 本文字数:1888 字

    阅读完需:约 6 分钟

Node.js 流基础

Node.js 本质上是异步和事件驱动的,因此非常擅长处理 I/O 密集型任务。如果您的应用程序需要执行 I/O 操作,可以利用 Node.js 提供的流(Streams)功能。

关键要点

  • Node.js 流是异步和事件驱动的,通过将数据分解为更小、更易管理的块来简化 I/O 操作

  • 流可分为可读(Readable)、可写(Writable)、双工(Duplex,既可读又可写)或转换(Transform,在传输过程中修改数据)

  • pipe()函数是 Node.js 流中的有用工具,允许从源读取数据并写入目标,而无需手动管理数据流

  • 现代 Node.js 提供了stream.pipeline()stream.finished()等实用程序以及基于 Promise 的 API,以实现更好的错误处理和流控制

  • 流可以与 async/await 模式一起使用,使代码更清晰、更易维护

什么是流

Node.js 中的流受到 Unix 管道的启发,提供了一种以流式方式从源读取数据并将其传输到目标的机制。简单地说,流就是一个 EventEmitter,并实现了一些特殊方法。根据实现的方法,流可以是可读、可写、双工或转换。

可读流

可读流允许您从源读取数据。源可以是任何东西:文件系统中的简单文件、内存中的缓冲区,甚至是另一个流。

从流中读取

从流中读取数据的最佳方法是监听 data 事件并附加回调:


const fs = require('fs');const readableStream = fs.createReadStream('file.txt');let data = '';
readableStream.on('data', function(chunk) { data += chunk;});
readableStream.on('end', function() { console.log(data);});
readableStream.on('error', (err) => { console.error('Error reading stream:', err);});
复制代码

现代 ECMAScript 特性

我们可以使用 async/await 重写上面的代码:


const fs = require('fs');const { Readable } = require('stream');const { promisify } = require('util');
const streamToString = async (stream) => { const chunks = []; for await (const chunk of stream) { chunks.push(typeof chunk === 'string' ? chunk : chunk.toString()); } return chunks.join('');};
async function readFile() { try { const readableStream = fs.createReadStream('file.txt'); const content = await streamToString(readableStream); console.log(content); } catch (err) { console.error('Error reading file:', err); }}
readFile();
复制代码

可写流

可写流允许您将数据写入目标。与可读流一样,它们也是 EventEmitter,并在不同点发出各种事件。

写入流

要将数据写入可写流,您需要在流实例上调用 write():


const fs = require('fs');const readableStream = fs.createReadStream('file1.txt');const writableStream = fs.createWriteStream('file2.txt');
readableStream.setEncoding('utf8');
readableStream.on('data', function(chunk) { writableStream.write(chunk);});
复制代码

处理背压(Backpressure)

更好的方法是处理背压:


const fs = require('fs');const readableStream = fs.createReadStream('file1.txt');const writableStream = fs.createWriteStream('file2.txt');
readableStream.setEncoding('utf8');
readableStream.on('data', function(chunk) { const canContinue = writableStream.write(chunk); if (!canContinue) { readableStream.pause(); }});
writableStream.on('drain', function() { readableStream.resume();});
readableStream.on('end', function() { writableStream.end();});
readableStream.on('error', (err) => { console.error('Read error:', err); writableStream.end();});
writableStream.on('error', (err) => { console.error('Write error:', err);});
复制代码

双工和转换流

双工流是可读和可写流的组合。它们维护两个独立的内部缓冲区,一个用于读取,一个用于写入,彼此独立运行。


转换流是一种特殊的双工流,可以在数据写入和读取时修改或转换数据。与双工流不同,双工流的输入和输出是分开的,而转换流的输出与其输入直接相关。


const { Transform } = require('stream');
const upperCaseTr = new Transform({ transform(chunk, encoding, callback) { this.push(chunk.toString().toUpperCase()); callback(); }});
process.stdin .pipe(upperCaseTr) .pipe(process.stdout);
复制代码

结论

这就是流的基础知识。流、管道和链是 Node.js 中最核心和最强大的功能。如果使用得当,流确实可以帮助您编写简洁且高性能的代码来执行 I/O 操作。只需确保正确处理流错误并适当关闭流以防止内存泄漏。更多精彩内容 请关注我的个人公众号 公众号(办公 AI 智能小助手)公众号二维码


办公AI智能小助手


用户头像

qife

关注

还未添加个人签名 2021-05-19 加入

还未添加个人简介

评论

发布
暂无评论
Node.js流基础:高效处理I/O操作的核心技术_node.js_qife_InfoQ写作社区