Reactor Pattern — Реактор
Главный паттерн архитектуры event loop в Node.js и браузере. Из синхронного кода делает асинхронный, крутя бесконечный цикл с очередью задач и обработчиков.
Проблема
JavaScript — практически синхронный язык. Для взаимодействия с внешним миром (I/O, таймеры, сеть) нужно:
- Принимать события асинхронно от ОС
- Связать низкоуровневые C-колбэки с JS-колбэками
- Не блокировать выполнение
Решение
Цикл, который демультиплексирует события от множества источников и диспатчит их зарегистрированным обработчикам.
- Очередь задач (handlers)
- На каждой итерации: пройти все handlers, вызвать их
- При завершении handler'а — забирает следующий
- Простой Reactor можно написать вручную, без libuv
Пример в JS
// Простейший Reactor — свой event loop
class Reactor {
tasks = ;
enqueue(fn) { this.tasks.push(fn); }
start {
while (this.tasks.length) {
const current = this.tasks;
this.tasks = ;
for (const fn of current) fn;
}
}
}
const r = new Reactor();
r.enqueue( => console.log('task 1'));
r.enqueue(() => {
console.log('task 2');
r.enqueue( => console.log('task 3 (added by task 2)'));
});
r.start(); // task 1, task 2, task 3
Где используется в JS-экосистеме
- libuv в Node.js — реализация Reactor + Proactor
- Браузерный event loop — Reactor над
requestAnimationFrame,setTimeout, microtasks - D8 (чистый V8) — без event loop, нужно писать свой
- Встраиваемый JS в Java, Qt, C# — без event loop, для встраивания нужен Reactor
- Игровые движки — свой event loop поверх V8
Подводные камни
- Reactor синхронный: каждая task должна быстро вернуть управление, иначе блокирует цикл.
- CPU-heavy задачи в Reactor блокируют I/O — нужен worker thread.
- Order matters: порядок обработки tasks в одной итерации важен для предсказуемости.
- Reactor vs Proactor: Reactor отдаёт готовность (event «можно читать»); Proactor отдаёт результат (event «вот прочитанные данные»).
Главные тезисы автора
- «Pattern Reactor позволяет перейти от синхронного кода к асинхронному».
- «Можем написать event loop сами» — Reactor реализуется в JS.
- JS — практически синхронный язык, Reactor превращает его в асинхронный.
- D8 / встраиваемый JS — без event loop, можно поэкспериментировать.
- Синхронный callback в
map/filter≠ асинхронный callback вsetTimeout. - Reactor → Proactor — следующий уровень: уже не просто event, а готовый результат.
🎓 Источники
- 🎓 Паттерн Reactor (реактор) как устроен Event Loop в Node.js · 2025-04-14
- Связь C-колбэков с JS-колбэками
- Синхронные vs асинхронные callback
- Без libuv — нужно писать свой event loop
- D8 и встраиваемый JS
- 🎓 Патерни українською Reactor для JavaScript та TypeScript · 2025-04-14