Skip to main content

Як з'єднати кілька потоків підряд?

Способи з'єднання потоків

Є два основні способи:

  1. Класичний - через .pipe()
  2. Сучасний і безпечний - через stream.pipeline()

1. З'єднання через .pipe()

Метод .pipe() - це найбазовіший спосіб "зв'язувати" потоки.

Він передає вивід одного потоку (Readable) на вхід іншого (Writable чи Transform):

javascript
const fs = require('fs'); const zlib = require('zlib'); fs.createReadStream('input.txt') // Readable .pipe(zlib.createGzip()) // Transform .pipe(fs.createWriteStream('output.txt.gz')); // Writable

Що відбувається:

  • createReadStream() читає файл частинами (chunks),
  • createGzip() стискає їх "на льоту",
  • createWriteStream() записує в новий файл.

Ланцюжок із кількох Transform-потоків

javascript
const fs = require('fs'); const { Transform } = require('stream'); const zlib = require('zlib'); // 1. Перетворюємо текст у верхній регістр const upper = new Transform({ transform(chunk, encoding, callback) { this.push(chunk.toString().toUpperCase()); callback(); }, }); // 2. Стискаємо результат const gzip = zlib.createGzip(); fs.createReadStream('input.txt') .pipe(upper) // Readable → Transform .pipe(gzip) // Transform → Transform .pipe(fs.createWriteStream('output.txt.gz')); // Transform → Writable

Кожен .pipe() повертає наступний потік, тож можна вибудовувати довгі ланцюжки.

2. З'єднання через pipeline()

Починаючи з Node.js v10, з'явився метод pipeline()stream), який робить те саме, але безпечніше й надійніше.

javascript
const { pipeline } = require('stream'); const fs = require('fs'); const zlib = require('zlib'); pipeline( fs.createReadStream('input.txt'), zlib.createGzip(), fs.createWriteStream('output.txt.gz'), (err) => { if (err) console.error('Помилка в потоці:', err); else console.log('Файл успішно оброблено!'); } );

Переваги pipeline() перед .pipe()

Особливість.pipe()pipeline()
Обробка помилокПотрібно вручнуАвтоматично
Завершення всіх потоків при помилціНемаєЄ
Callback / Promise по завершеннюНемаєЄ
Підтримка async/await (stream/promises)НемаєЄ

3. Асинхронний варіант (stream/promises)

Сучасний спосіб із await (Node.js 15+):

javascript
import { pipeline } from 'stream/promises'; import fs from 'fs'; import zlib from 'zlib'; import { Transform } from 'stream'; const upper = new Transform({ transform(chunk, _, cb) { cb(null, chunk.toString().toUpperCase()); }, }); await pipeline( fs.createReadStream('input.txt'), upper, zlib.createGzip(), fs.createWriteStream('output.txt.gz') ); console.log('Усі потоки успішно завершено');

Узагальнена схема ланцюжка потоків

javascript
ReadableTransformTransformWritable ↓ ↓ ↓ ↓ Джерело Фільтр 1 Фільтр 2 Приймач

Кожен Transform може:

  • стискати,
  • шифрувати,
  • фільтрувати,
  • парсити JSON,
  • форматувати текст,
  • логувати дані тощо.

Ключові правила при з'єднанні потоків

  1. Порядок важливий - дані течуть зліва направо.
  2. Кожен .pipe() повертає наступний потік, що дозволяє будувати ланцюжки.
  3. Не забувай про помилки, якщо використовуєш .pipe() без pipeline():
javascript
stream.on('error', console.error);
  1. Використовуй pipeline() для продакшену - він сам закриє все в разі збою.

Коротка відповідь

Для співбесіди
Premium

Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.