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

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

  • Курсы
    • FrontendИконка стрелки
    • AI разработкаИконка стрелки
    • BackendИконка стрелки
    • DevOpsИконка стрелки
    • MobileИконка стрелки
    • ТестированиеИконка стрелки
    • Soft-skillsИконка стрелки
    • ДизайнИконка стрелки
    Иконка слояПерейти в каталог курсов
  • Бесплатно
    • Курсы
    • JavaScript Основы разработкиPython Основы PythonCSS CSS FlexboxКарта развитияВопросы для собеседований
    • База знанийИконка стрелки
    • Новостные рассылкиИконка стрелки
  • PurpleSchool — курсы программирования онлайн
    • AI для кодаНовое
    • Сообщество
    • PurpleПлюс
    • AI Собеседование
    • 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.

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

    Комментарии

    0

    Постройте личный план изучения HTML и CSS - полный курс по вёрстке с нуля до уровня Middle — бесплатно!

    HTML и CSS - полный курс по вёрстке с нуля — часть карты развития Frontend, Mobile

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

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

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

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

    CSS Flexbox

    Антон Ларичев
    Гарантия
    Бонусы
    иконка звёздочки рейтинга4.9
    бесплатно
    Подробнее
    изображение курса

    Основы JavaScript

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

    Продвинутый JavaScript

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

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

    Картинка поста Асинхронность в JavaScript: Event Loop, промисы и async/await
    Иконка аватараАнтон
    Иконка календаря04 июня 2026
    JavaScriptАсинхронностьEvent Loop+ 2middleИконка уровня middle

    Асинхронность в JavaScript: Event Loop, промисы и async/await

    Разбираем асинхронность в JavaScript: как работает Event Loop, чем промисы лучше колбэков и зачем нужен async/await на практике.

    Иконка чипа0
    Иконка глаза164
    Иконка комментариев0
    Картинка поста WebSocket на Node.js: пишем чат и real-time уведомления
    Иконка аватараАнтон
    Иконка календаря09 июня 2026
    WebSocketNode.jsReal-time+ 1middleИконка уровня middle

    WebSocket на Node.js: пишем чат и real-time уведомления

    WebSocket на Node.js: разбираем протокол, пишем чат на ws-сервере и систему real-time уведомлений с reconnect и heartbeat.

    Иконка чипа+1
    Иконка глаза320
    Иконка комментариев0
    Картинка поста Архитектура Node.js: слои, модули и Dependency Injection
    Иконка аватараАнтон
    Иконка календаря08 июня 2026
    Node.jsАрхитектураBackend+ 1middleИконка уровня middle

    Архитектура Node.js: слои, модули и Dependency Injection

    Архитектура Node.js приложения: разбираем слоистую структуру, разделение на модули и применение Dependency Injection для масштабируемого кода.

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