Коротка відповідь
juniorStreams — це об’єкти, що послідовно читають або записують дані. Вони дозволяють працювати з великими файлами чи мережевими потоками без завантаження всього в пам’ять. Читання/запис відбувається через події 'data', 'end' і 'error'. `fs.createReadStream('file.txt').pipe(process.stdout);`
Повне пояснення
Що це і навіщо
Streams у Node.js – це абстракція для послідовної обробки великих потоків даних (файли, мережеві з’єднання, процеси). Вони дозволяють читати/записувати дані частинами, не блокуючи event‑loop і зменшуючи використання пам’яті.
Ключові принципи/терміни
- Readable stream – читає дані.
- Writable stream – записує дані.
- Duplex stream – одночасно читає й пише (наприклад, net.Socket).
- Transform stream – обробляє дані між читанням і записом (gzip, cipher).
- Події:
data,end,error,close.
Як це працює
- При створенні Readable stream Node.js відкриває ресурс (файл, socket) і починає генерувати
data‑події. - Кожна
data‑подія містить буфер (Buffer або string). Після обробки можна викликатиstream.resume()/pause(). - Коли дані закінчуються, генерується
end‑подія. - Якщо виникає помилка –
error‑подія.
Практика і реалізація (JS/TS)
import { createReadStream, createWriteStream } from 'fs';
const src = createReadStream('big.txt');
const dst = createWriteStream('copy.txt');
src.pipe(dst);
import { Transform } from 'stream';
const upper = new Transform({
transform(chunk, _, cb) { cb(null, chunk.toString().toUpperCase()); }
});
process.stdin.pipe(upper).pipe(process.stdout);
Тестування
- Unit: мокати
Readable/Writableза допомогоюstream.PassThrough(). - Integration: перевірити, що файл копіюється без помилок.
import { PassThrough } from 'stream';
const input = new PassThrough();
input.end('abc');
const output: string[] = [];
input.on('data', d => output.push(d.toString()));
expect(output).toEqual(['abc']);
Безпека і приватність
- Не передавайте необроблені дані з мережевих потоків без валідації.
- Використовуйте
stream.pipeline()для автоматичного закриття ресурсів у випадку помилки.
Особливості в контексті Node.js
- Всі I/O‑операції у Node.js реалізовані через streams.
fsмодуль надаєcreateReadStream,createWriteStream,openSyncтощо.- Мережеві сокети (
net.Socket) є Duplex streams.
Оптимізація і edge cases
- Використовуйте
highWaterMarkдля регулювання буферизації. - Уникайте «backpressure» – перевіряйте повернуте значення
write(). - Для великих файлів використовуйте
stream.pipeline()замість простогоpipe().
Диагностика
- Якщо дані не потрапляють, перевірте
end‑подію. - Якщо поток «завис» – перевірте, чи не заблоковано
write(). - Переконайтеся, що ресурс (файл/сокет) відкритий.
Часті помилки (8)
- Не закривати
Writable→ memory leak. - Використання
write()без перевірки повернутого значення → backpressure. - Не обробляти
error→ процес падає. - Відсутність
end‑події → нескінченний цикл читання. - Неправильне
highWaterMark→ надмірна пам’ять. - Перевантаження
pipe()безpipeline()→ не закриває ресурси. - Відсутність
encodingу Readable → буфери замість string. - Не використання
async/awaitз потоками → синхронна блокування.
Cheatsheet
stream.readable– читає.stream.writable– пише.stream.pipe(dest)– підключає.stream.pipeline(..., callback)– безпечне з’єднання.stream.Transform– обробка.
Follow‑up питання
- Як працює backpressure у streams?
- Чому
pipeline()краще за простеpipe()? - Як обробляти помилки у Transform stream?