Ответ
Node.js использует event-driven, non-blocking I/O модель, основанную на event loop. Это single-threaded подход, где операции ввода-вывода выполняются асинхронно через callbacks, promises или async/await.
Пример с EventEmitter (паттерн Observer):
const EventEmitter = require('events');
const emitter = new EventEmitter();
emitter.on('message', (data) => {
console.log('Received:', data);
});
emitter.emit('message', 'Hello, Node.js!');
Для работы с потоками (streams) используется backpressure для контроля скорости передачи данных.
Если нужна гарантированная доставка (например, RabbitMQ/Kafka), используют message brokers с подтверждениями (ACKs).
В веб-сокетах (WebSocket) применяется full-duplex связь в реальном времени.
Ответ 18+ 🔞
А, Node.js, говоришь? Ну это ж классика, ёпта! Слушай, представь себе бармена-одиночку в адской забегаловке в пятницу вечером. Один чувак, а заказов — овердохуища. Так вот этот бармен — и есть Node.js, single-threaded, блядь.
Вместо того чтобы взять одного клиента, налить ему пива, ждать, пока он допьёт, и только потом обслуживать следующего (это blocking I/O, старьё), наш парень работает по-умному. Event-driven, неблокирующая модель, ядрёна вошь! Подходит клиент, заказывает сложный коктейль. Бармен кидает: «Окей, готовлю!» — и сразу поворачивается к следующему. Пока первый коктейль там взбивается-смешивается, он уже второму пиво налил, третьему счёт выписал. Всё через колбэки, промисы или async/await — это как он себе напоминалки о заказах оставляет. Главное — не блокировать всю очередь из-за одного долгого заказа.
Вот, смотри, как они там событиями швыряются, прямо паттерн «Наблюдатель»:
const EventEmitter = require('events');
const emitter = new EventEmitter();
emitter.on('message', (data) => {
console.log('Received:', data);
});
emitter.emit('message', 'Hello, Node.js!');
Видал? Создал «излучатель событий» (EventEmitter), подписался на событие 'message' через .on() — это типа «слушай, как только кто-то крикнет "message", ты делай вот это». А потом .emit() — это сам крикнул. Всё, приёмник сработал. Проще пареной репы, а мощь — хуй с горы!
А ещё у них там потоки (streams) — это вообще песня. Представь, ты пытаешься из бочки в стакан воду перелить. Если лить со всей дури, стакан переполнится, всё на пол польётся. Так вот backpressure — это такая хитрая система, когда стакан сам говорит: «Эй, бочка, притормози, я ещё не готов!». Поток-приёмник контролирует скорость потока-источника, чтобы память не переполнить. Без этого — пипец, приложение сожрёт всю оперативку и накрылось бы медным тазом.
Ну а если тебе надо не просто крикнуть в пространство, а чтобы сообщение точно дошло, типа гарантированно? Например, заказ в интернет-магазине. Тут уже нужны серьёзные ребята — message brokers, типа RabbitMQ или Kafka. Ты им сообщение отдал, а они тебе квитанцию (ACK) присылают: «Чувак, всё ок, мы твой заказ приняли, обрабатываем». Без этого — доверия ебать ноль, вдруг сообщение потеряется по дороге.
И, конечно, веб-сокеты (WebSocket). Это когда нужно не просто разок запрос кинуть и ответ получить, а чтобы канал связи был постоянный, в реальном времени. Типа чат или онлайн-игра. Full-duplex связь, ёбааать! Это как телефонный разговор: ты говоришь и одновременно слышишь, что тебе отвечают. Не как в старом интернете, где отправил запрос — жди ответа, как будто письмо по почте послал.
Вот такая, блядь, философия. Один поток, но за счёт асинхронности и событийной модели выжимает из железа всё, до последней капли. Главное — не накосячить с блокирующими операциями, а то весь этот ебаный event loop встанет колом, и будет тебе хиросима вместо высоких нагрузок.