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, а готовый результат.

🎓 Источники

См. также