PurpleSchool — курсы программирования онлайн
  • Бесплатно
    • Курсы
    • JavaScript Основы разработкиPython Основы PythonCSS CSS FlexboxКарта развития
    • База знанийИконка стрелки
    • Новостные рассылкиИконка стрелки
  • Карьерные пути
    • Frontend React разработчик
    • Frontend Vue разработчик
    • Backend разработчик Node.js
    • Fullstack разработчик React / Node.js
    • Mobile разработчик React Native
    • Backend разработчик Golang
    • Devops инженер
    • Backend разработчик Python
  • О нас
    • Отзывы
    • Реферальная программа
    • О компании
    • Контакты
  • Иконка открытия меню
    • Сообщество
    • PurpleПлюс
    • AI тренажёр
    • Проекты
PurpleSchool — платформа бесплатных roadmap и курсов для разработчиков
ютуб иконка
Telegram иконка
VK иконка
VK иконка
Курсы
ГлавнаяКаталог курсовFrontendBackendFullstack
Практика
КарьераПроектыPurpleПлюс
Материалы
БлогБаза знаний
Документы
Договор офертаПолитика конфиденциальностиПроверка сертификатаМиграция курсовРеферальная программа
Реквизиты
ИП Ларичев Антон АндреевичИНН 773373765379contact@purpleschool.ru

PurpleSchool © 2020 -2026 Все права защищены

  • Курсы
    • FrontendИконка стрелки
    • AI разработкаИконка стрелки
    • BackendИконка стрелки
    • DevOpsИконка стрелки
    • MobileИконка стрелки
    • ТестированиеИконка стрелки
    • Soft-skillsИконка стрелки
    • ДизайнИконка стрелки
    Иконка слояПерейти в каталог курсов
  • PurpleSchool — курсы программирования онлайн
    • Сообщество
    • PurpleПлюс
    • AI тренажёр
    • Проекты
    Главная
    Сообщество
    Event Loop в Node.js: как работает и зачем это знать

    Event Loop в Node.js: как работает и зачем это знать

    Аватар автора Event Loop в Node.js: как работает и зачем это знать

    Антон Ларичев

    Иконка календаря04 мая 2026
    Node.jsJavaScriptEvent LoopАсинхронностьBackendmiddleИконка уровня middle
    Картинка поста Event Loop в Node.js: как работает и зачем это знать

    Введение

    Event Loop — сердце Node.js, механизм, который позволяет однопоточной среде выполнения обрабатывать тысячи одновременных операций ввода-вывода. Понимание его работы критично для любого backend-разработчика: без этого знания легко написать код, который блокирует сервер, теряет производительность или ведёт себя непредсказуемо под нагрузкой.

    Node.js построен поверх движка V8 и библиотеки libuv. Именно libuv реализует Event Loop, делегируя тяжёлые операции (файловая система, сеть, DNS) пулу потоков и системным вызовам, а результаты возвращает в основной поток через очереди колбэков.

    Архитектура: однопоточность и неблокирующий I/O

    JavaScript в Node.js выполняется в одном потоке. Это значит, что в любой момент времени работает ровно одна функция. Чтобы при этом не простаивать на медленных операциях, Node перекладывает их на ядро ОС или на отдельные потоки libuv, а основной поток продолжает обрабатывать другие задачи.

    const fs = require('fs');
    
    // Неблокирующее чтение: основной поток свободен
    fs.readFile('/etc/hosts', (err, data) => {
      console.log('Файл прочитан');
    });
    
    console.log('Запрос отправлен');
    // Сначала выведется 'Запрос отправлен', потом 'Файл прочитан'
    

    Фазы Event Loop

    Event Loop проходит фазы по кругу. На каждой итерации (tick) выполняются колбэки из соответствующей очереди.

    1. Timers

    Выполняются колбэки setTimeout и setInterval, у которых истёк таймер. Важно: указанное время — это минимальная задержка, а не точная.

    2. Pending callbacks

    Колбэки некоторых системных операций — например, ошибки TCP-соединений.

    3. Idle, prepare

    Внутренние нужды libuv, разработчику недоступны.

    4. Poll

    Центральная фаза: получение новых событий ввода-вывода и выполнение их колбэков. Если очередь пуста, цикл может ждать здесь новых событий.

    5. Check

    Выполняются колбэки setImmediate. Они гарантированно сработают сразу после фазы poll.

    6. Close callbacks

    Колбэки закрытия — например, socket.on('close', ...).

    setTimeout(() => console.log('timeout'), 0);
    setImmediate(() => console.log('immediate'));
    
    // Порядок не гарантирован вне I/O контекста,
    // но внутри I/O колбэка setImmediate всегда раньше setTimeout
    

    Микрозадачи: process.nextTick и Promise

    Помимо фаз Event Loop существуют две очереди микрозадач, которые обрабатываются между любыми операциями:

    • process.nextTick — наивысший приоритет, выполняется до всего остального.
    • Promise jobs (.then, await) — следом за nextTick.
    setTimeout(() => console.log('timeout'), 0);
    setImmediate(() => console.log('immediate'));
    Promise.resolve().then(() => console.log('promise'));
    process.nextTick(() => console.log('nextTick'));
    
    console.log('sync');
    
    // Вывод:
    // sync
    // nextTick
    // promise
    // timeout (или immediate)
    // immediate (или timeout)
    

    Микрозадачи опустошаются полностью между фазами. Это удобно, но опасно: рекурсивный process.nextTick может полностью заблокировать Event Loop, не давая обработать ни одно I/O событие.

    Thread Pool и тяжёлые операции

    libuv держит пул потоков (по умолчанию 4, регулируется через UV_THREADPOOL_SIZE). В нём выполняются операции, которые ОС не умеет делать асинхронно: fs.*, crypto.pbkdf2, zlib, DNS через dns.lookup.

    const crypto = require('crypto');
    
    const start = Date.now();
    for (let i = 0; i < 4; i++) {
      crypto.pbkdf2('pass', 'salt', 100000, 64, 'sha512', () => {
        console.log(`Задача ${i}: ${Date.now() - start}ms`);
      });
    }
    // Все 4 задачи завершатся примерно одновременно — пул вмещает 4 потока
    // Пятая задача будет ждать освобождения потока
    

    Частые ошибки

    Блокирующий код в основном потоке

    Тяжёлые синхронные вычисления (большие циклы, JSON.parse мегабайтных строк, синхронные fs.readFileSync) полностью останавливают Event Loop. Сервер перестаёт отвечать на запросы.

    // Плохо: блокирует поток на сотни миллисекунд
    app.get('/hash', (req, res) => {
      const hash = crypto.pbkdf2Sync('pass', 'salt', 1000000, 64, 'sha512');
      res.send(hash.toString('hex'));
    });
    
    // Хорошо: асинхронная версия отдаёт работу пулу потоков
    app.get('/hash', (req, res) => {
      crypto.pbkdf2('pass', 'salt', 1000000, 64, 'sha512', (err, hash) => {
        res.send(hash.toString('hex'));
      });
    });
    

    Голодание I/O через nextTick

    Рекурсивный process.nextTick не даёт циклу выйти за пределы текущей фазы.

    // Опасно: I/O колбэки никогда не выполнятся
    function loop() {
      process.nextTick(loop);
    }
    loop();
    

    Путаница setTimeout(fn, 0) и setImmediate

    Вне I/O контекста порядок не детерминирован. Если нужен гарантированный порядок «после текущего I/O» — используйте setImmediate.

    Игнорирование размера thread pool

    Если приложение активно использует crypto или fs, дефолтных 4 потоков мало. Увеличьте через переменную окружения:

    UV_THREADPOOL_SIZE=16 node app.js
    

    Заключение

    Event Loop — не магия, а строгая последовательность фаз с предсказуемыми правилами. Зная порядок Timers → Poll → Check, приоритет микрозадач и ограничения thread pool, вы сможете писать Node.js-приложения, которые держат нагрузку и не падают под пиками. Главное правило: никогда не блокируйте основной поток — выносите тяжёлые вычисления в worker threads, отдельные сервисы или асинхронные API.

    Иконка глаза11

    Комментарии

    0

    Постройте личный план изучения React state менеджер Zustand до уровня Middle — бесплатно!

    React state менеджер Zustand — часть карты развития Frontend

    • step100+ шагов развития
    • lessons30 бесплатных лекций
    • lessons300 бонусных рублей на счет

    Бесплатные лекции

    Лучшие курсы по теме

    изображение курса

    Vue 3 и Pinia

    Антон Ларичев
    AI-тренажерыAI-тренажеры
    Практика в студииПрактика в студии
    Гарантия
    Бонусы
    иконка звёздочки рейтинга4.9
    3 999 ₽ 6 990 ₽
    Подробнее
    изображение курса

    Next.js - с нуля

    Антон Ларичев
    AI-тренажерыAI-тренажеры
    Практика в студииПрактика в студии
    Гарантия
    Бонусы
    иконка звёздочки рейтинга4.7
    3 999 ₽ 6 990 ₽
    Подробнее
    изображение курса

    Feature-Sliced Design

    Антон Ларичев
    AI-тренажерыAI-тренажеры
    Практика в студииПрактика в студии
    Гарантия
    Бонусы
    иконка звёздочки рейтинга4.5
    3 999 ₽ 6 990 ₽
    Подробнее

    Похожие статьи

    Картинка поста PostgreSQL + Prisma: работа с БД в TypeScript проекте
    Иконка аватараАнтон
    Иконка календаря27 апреля 2026
    PostgreSQLPrismaTypeScript+ 3juniorИконка уровня junior

    PostgreSQL + Prisma: работа с БД в TypeScript проекте

    PostgreSQL и Prisma — мощная связка для работы с базой данных в TypeScript. Разберём настройку, схему, миграции и типобезопасные запросы.

    Иконка чипа0
    Иконка глаза243
    Иконка комментариев0
    Картинка поста Zustand vs Redux Toolkit: что выбрать в 2024 году
    Иконка аватараАнтон
    Иконка календаря26 апреля 2026
    ReactState ManagementZustand+ 2middleИконка уровня middle

    Zustand vs Redux Toolkit: что выбрать в 2024 году

    Zustand vs Redux Toolkit — сравниваем две популярные библиотеки управления состоянием в React: архитектура, производительность и когда что выбрать.

    Иконка чипа0
    Иконка глаза205
    Иконка комментариев0
    Картинка поста Kubernetes для разработчиков: деплой без знания DevOps
    Иконка аватараАнтон
    Иконка календаря25 апреля 2026
    KubernetesDevOpsDocker+ 3middleИконка уровня middle

    Kubernetes для разработчиков: деплой без знания DevOps

    Kubernetes для разработчиков: как задеплоить приложение в k8s без глубоких знаний DevOps — пошаговый разбор с примерами манифестов.

    Иконка чипа0
    Иконка глаза238
    Иконка комментариев0
    Иконка чипа0