Ответ
В Node.js есть четыре основных типа потоков, реализующих соответствующие абстракции:
-
Readable — поток для чтения данных (например, из файла, HTTP-запроса).
const fs = require('fs'); const readableStream = fs.createReadStream('./input.txt'); -
Writable — поток для записи данных (например, в файл, HTTP-ответ).
const writableStream = fs.createWriteStream('./output.txt'); -
Duplex — поток, который одновременно является и Readable, и Writable (например, TCP-сокет).
const { Duplex } = require('stream'); const myDuplex = new Duplex({ read(size) { /* ... */ }, write(chunk, encoding, callback) { /* ... */ } }); -
Transform — особый тип Duplex-потока, предназначенный для модификации данных на лету (например, сжатие, шифрование).
const { Transform } = require('stream'); const upperCaseTransform = new Transform({ transform(chunk, encoding, callback) { this.push(chunk.toString().toUpperCase()); callback(); } });
Потоки также могут работать в двух режимах:
- Paused (остановленный): данные читаются только после вызова
.read(). - Flowing (текущий): данные автоматически передаются в обработчики событий, такие как
'data'.
Использование потоков критически важно для эффективной обработки больших объемов данных без загрузки всего набора в память, что является ключевым преимуществом Node.js.
Ответ 18+ 🔞
А, ну это ж классика, ёпта! Сидишь такой, пишешь на Node.js, думаешь — красота, всё летает. А потом бац — файл на 10 гигов подсовывают, и твоё приложение накрывается медным тазом, потому что всю эту овердохуищу данных в память пытается загнать. Вот тут-то и вспоминаешь про потоки, как про молитву.
Смотри, в Node.js есть четыре главных типа этих самых потоков. Не пугайся, всё логично, как в жизни.
-
Readable — это такой поток, который только сосёт, прости за выражение. Данные откуда-то тянет. С файла, из интернета, откуда угодно.
const fs = require('fs'); const readableStream = fs.createReadStream('./input.txt');Вот он создался и молчит, ждёт команды. Как будто водопроводный кран открыли, но вода ещё не побежала.
-
Writable — полная противоположность. Это поток, который только даёт. В него можно писать, и он это куда-то пристроит — в файл, в ответ сервера.
const writableStream = fs.createWriteStream('./output.txt');Представь дыру в стене, куда всё проваливается. Вот это он и есть, только полезный.
-
Duplex — а это уже хитрая жопа. Он и сосёт, и даёт одновременно. Классический пример — сетевое соединение, тот же TCP-сокет. Ты ему данные шлёшь, а он тебе в ответ что-то своё присылает.
const { Duplex } = require('stream'); const myDuplex = new Duplex({ read(size) { /* ... */ }, write(chunk, encoding, callback) { /* ... */ } });Универсальный солдат, бля. И туда, и обратно.
-
Transform — это вообще магия, особый подвид Duplex'а. Он берёт данные, как-то их по-своему ебёт на лету, и выдаёт уже изменённые. Сжатие, шифрование — вот это всё его рук дело.
const { Transform } = require('stream'); const upperCaseTransform = new Transform({ transform(chunk, encoding, callback) { this.push(chunk.toString().toUpperCase()); callback(); } });Закинул ему "привет", а получил "ПРИВЕТ". Красота!
А ещё у них, у этих потоков, два режима работы есть, смотри не перепутай:
- Paused (остановленный): Сам ничего не делает, сидит как партизан. Чтобы данные пошли, надо ему явно сказать
.read()— ну-ка, падла, выдавай что там у тебя! - Flowing (текущий): Включил и поехал. Данные сами начинают литься рекой в обработчик события
'data'. Главное — не утонуть, вовремя этот поток притормозить, а то сожрёт всю память.
Вот вся суть в чём, чувак: если ты не хочешь, чтобы твоё приложение бздело и падало под нагрузкой, ты должен эти потоки использовать. Вместо того чтобы весь огромный файл в оперативку тащить, ты его по кусочкам, через эти шланги, прогоняешь. Обработал кусок — выкинул из памяти, взял следующий. Эффективность — пиздец! Именно за это Node.js и любят. Так что не ленись, разбирайся с этой темой, а то будет тебе хиросима, а не сервис.