mcpField
S
streams

streams

github.com/pluginagentmarketplace开发245 次安装42 周前更新
代码仓库

关于 streams

streams 是面向 Node.js 开发者的流编程学习技能,适用于处理大型文件、实时数据和组合式管道。内容涵盖流类型、背压、错误处理及 HTTP 流和异步迭代器等实践模式。

主要功能

  1. 01Readable、Writable、Transform 和 Duplex 流
  2. 02文件与 HTTP 流处理
  3. 03背压与错误处理
  4. 04管道组合
  5. 05对象模式与异步迭代器
  6. 06自定义流实现

适用场景

  1. 01以有限内存处理大型文件
  2. 02构建实时数据管道
  3. 03通过 HTTP 响应传输文件
  4. 04转换对象或数据块

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/pluginagentmarketplace/custom-plugin-nodejs --skill streams

安装后在 Claude Code 中输入/streams确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

assets/
config.yaml
schema.json
references/
GUIDE.md
PATTERNS.md
scripts/
validate.py

详细介绍

Node.js 流技能

掌握流,以高效利用内存的方式处理大型文件和实时数据,并构建可组合的数据管道。

快速入门

流分为 4 种类型:

  1. Readable - 数据来源(文件、HTTP 请求)
  2. Writable - 数据目标(文件、HTTP 响应)
  3. Transform - 在数据传输过程中修改数据
  4. 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