关于 streams
streams 是面向 Node.js 开发者的流编程学习技能,适用于处理大型文件、实时数据和组合式管道。内容涵盖流类型、背压、错误处理及 HTTP 流和异步迭代器等实践模式。
主要功能
- 01Readable、Writable、Transform 和 Duplex 流
- 02文件与 HTTP 流处理
- 03背压与错误处理
- 04管道组合
- 05对象模式与异步迭代器
- 06自定义流实现
适用场景
- 01以有限内存处理大型文件
- 02构建实时数据管道
- 03通过 HTTP 响应传输文件
- 04转换对象或数据块
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ pluginagentmarketplace/ custom-plugin-nodejs --skill streams安装后在 Claude Code 中输入/streams确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
assets/config.yamlschema.jsonreferences/GUIDE.mdPATTERNS.mdscripts/validate.py详细介绍
Node.js 流技能
掌握流,以高效利用内存的方式处理大型文件和实时数据,并构建可组合的数据管道。
快速入门
流分为 4 种类型:
- Readable - 数据来源(文件、HTTP 请求)
- Writable - 数据目标(文件、HTTP 响应)
- Transform - 在数据传输过程中修改数据
- Duplex - 既可读又可写
核心概念
可读流
const fs = require('fs');
// Create readable stream
const readStream = fs.createReadStream('large-file.txt', {
encoding: 'utf8',
highWaterMark: 64 * 1024 // 64KB chunks
});
// Event-based consumption
readStream.on('data', (chunk) => {
console.log(`Received ${chunk.length} bytes`);
});
readStream.on('end', () => {
console.log('Finished reading');
});
readStream.on('error', (err) => {
console.error('Read error:', err);
});
可写流
const writeStream = fs.createWriteStream('output.txt');
// Write data
writeStream.write('Hello, ');
writeStream.write('World!\n');
writeStream.end(); // Signal end
// Handle backpressure
const ok = writeStream.write(data);
if (!ok) {
// Wait for drain event before writing more
writeStream.once('drain', () => {
continueWriting();
});
}
转换流
const { Transform } = require('stream');
// Custom transform: uppercase text
const upperCase = new Transform({
transform(chunk, encoding, callback) {
this.push(chunk.toString().toUpperCase());
callback();
}
});
// Usage
fs.createReadStream('input.txt')
.pipe(upperCase)
.pipe(fs.createWriteStream('output.txt'));
学习路线
初级(1-2 周)
- ✅ 了解流的类型
- ✅ 读写文件流
- ✅ 基本的管道操作
- ✅ 处理流事件
中级(3-4 周)
- ✅ 转换流
- ✅ 处理背压
- ✅ 对象模式流
- ✅ 管道工具
高级(5-6 周)
- ✅ 自定义流实现
- ✅ 异步迭代器
- ✅ Web Streams API
- ✅ 性能优化
管道(推荐)
const { pipeline } = require('stream/promises');
const zlib = require('zlib');
// Compose streams with error handling
async function compressFile(input, output) {
await pipeline(
fs.createReadStream(input),
zlib.createGzip(),
fs.createWriteStream(output)
);
console.log('Compression complete');
}
// With transform
await pipeline(
fs.createReadStream('data.csv'),
csvParser(),
transformRow(),
jsonStringify(),
fs.createWriteStream('data.json')
);
带错误处理的管道
const { pipeline } = require('stream');
pipeline(
source,
transform1,
transform2,
destination,
(err) => {
if (err) {
console.error('Pipeline failed:', err);
} else {
console.log('Pipeline succeeded');
}
}
);
HTTP 流式处理
const http = require('http');
const fs = require('fs');
// Stream file as HTTP response
http.createServer((req, res) => {
const filePath = './video.mp4';
const stat = fs.statSync(filePath);
res.writeHead(200, {
'Content-Type': 'video/mp4',
'Content-Length': stat.size
});
// Stream instead of loading entire file
fs.createReadStream(filePath).pipe(res);
}).listen(3000);
// Stream HTTP request body
http.createServer((req, res) => {
const writeStream = fs.createWriteStream('./upload.bin');
req.pipe(writeStream);
req.on('end', () => {
res.end('Upload complete');
});
}).listen(3001);
对象模式流
const { Transform } = require('stream');
const jsonParser = new Transform({
objectMode: true,
transform(chunk, encoding, callback) {
try {
const obj = JSON.parse(chunk);
this.push(obj);
callback();
} catch (err) {
callback(err);
}
}
});
// Process objects instead of buffers
const processRecords = new Transform({
objectMode: true,
transform(record, encoding, callback) {
record.processed = true;
record.timestamp = Date.now();
this.push(record);
callback();
}
});
异步迭代器
const { Readable } = require('stream');
// Create from async iterator
async function* generateData() {
for (let i = 0; i < 100; i++) {
yield { id: i, data: `item-${i}` };
}
}
const stream = Readable.from(generateData(), { objectMode: true });
// Consume with for-await
async function processStream(readable) {
for await (const chunk of readable) {
console.log('Processing:', chunk);
}
}
背压处理
const readable = fs.createReadStream('huge-file.txt');
const writable = fs.createWriteStream('output.txt');
readable.on('data', (chunk) => {
// Check if writable can accept more data
const canContinue = writable.write(chunk);
if (!canContinue) {
// Pause reading until writable is ready
readable.pause();
writable.once('drain', () => {
readable.resume();
});
}
});
// Or use pipeline (handles automatically)
pipeline(readable, writable, (err) => {
if (err) console.error('Error:', err);
});
自定义可读流
const { Readable } = require('stream');
class DatabaseStream extends Readable {
constructor(query, options) {
super({ ...options, objectMode: true });
this.query = query;
this.cursor = null;
}
async _read() {
if (!this.cursor) {
this.cursor = await db.collection('items').find(this.query).cursor();
}
const doc = await this.cursor.next();
if (doc) {
this.push(doc);
} else {
this.push(null); // Signal end
}
}
}
// Usage
const dbStream = new DatabaseStream({ status: 'active' });
for await (const item of dbStream) {
console.log(item);
}
单元测试模板
const { Readable, Transform } = require('stream');
const { pipeline } = require('stream/promises');
describe('Stream Processing', () => {
it('should transform data correctly', async () => {
const input = Readable.from(['hello', 'world']);
const chunks = [];
const upperCase = new Transform({
transform(chunk, enc, cb) {
this.push(chunk.toString().toUpperCase());
cb();
}
});
await pipeline(
input,
upperCase,
async function* (source) {
for await (const chunk of source) {
chunks.push(chunk.toString());
}
}
);
expect(chunks).toEqual(['HELLO', 'WORLD']);
});
});
故障排查
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 内存无限增长 | 没有背压 | 使用管道或处理 drain |
| 数据丢失 | 未捕获错误 | 使用带错误回调的管道 |
| 处理缓慢 | 块大小过小 | 增大 highWaterMark |
| 流挂起 | 缺少 end() 调用 | 调用 writable.end() |
适用场景
在以下情况下使用流:
- 处理大型文件(GB+)
- 实时数据处理
- 内存受限的环境
- 构建数据管道
- 处理 HTTP 请求/响应
相关技能
- 异步编程(异步模式)
- 性能优化(内存效率)
- Express REST API(流式响应)
资源
评论
支持 Markdown