Гид по технологиям

Как приостановить выполнение в Node.js: setTimeout, async/await и sleep-promise

• 4 min read • Node.js • Обновлено 05 Dec 2025
Пауза в Node.js: setTimeout, async/await, sleep-promise
Пауза в Node.js: setTimeout, async/await, sleep-promise

Мелкие деревянные клавиши с надписью «пауза» в миске

Коротко о задаче

JavaScript не предоставляет встроенной функции sleep(), как некоторые другие языки. Вместо этого используются таймеры и промисы. Ниже — три рабочих подхода с примерами, плюс практические советы, когда что использовать.

Использование setTimeout для задержки

Функция setTimeout планирует выполнение кода через заданное число миллисекунд. Она принимает функцию и задержку в миллисекундах. Синтаксис:

setTimeout(function, timeInMs);

Простой пример функции, которая печатает сообщение в консоль:

function printSentence() {
  console.log("Using setTimeout()");
}

setTimeout(printSentence, 2000); // 2000 мс = 2 секунды

Важно: setTimeout не блокирует поток выполнения. Это значит, что остальной код продолжит выполняться, и запланированная функция попадёт в очередь событий после истечения задержки и когда стек вызовов будет пуст.

Насколько точен setTimeout?

setTimeout обеспечивает минимум задержки, но не гарантию точного срабатывания в миллисекунду. Если поток занят другими синхронными операциями, выполнение отложенной функции может произойти позже запрошенного времени.

Пример поведения:

console.log("Hello World!");

function printSentence() {
  console.log("Using setTimeout()");
}

setTimeout(printSentence, 2000);
console.log("Done");

Вывод в консоль будет:

Hello World!
Done
Using setTimeout()

Если нужен строго последовательный вывод с паузой между строками, setTimeout в чистом виде не даст блока выполнения.

Блокирующая «пауза» через busy-wait (не рекомендована для основного потока)

Можно симулировать блокирующую задержку циклом do…while, но это сильно грузит CPU и блокирует весь Node-процесс:

function delay(ms) {
  const date = Date.now();
  let currentDate = null;

  do {
    currentDate = Date.now();
  } while (currentDate - date < ms);
}

console.log("Hello World");
delay(2000); // блокирует поток на 2 секунды
console.log("Will be printed after 2 seconds!");

Используйте такой подход только в отдельных воркерах или для очень специфичных задач, где блокировка потока допустима.

Использование async/await для паузы

await приостанавливает выполнение асинхронной функции до тех пор, пока промис не перейдёт в состояние resolved. Это даёт чистый синтаксис и не блокирует весь поток выполнения.

Пример функции delay на промисе и её использование с async/await:

function delay(time) {
  return new Promise(resolve => setTimeout(resolve, time));
}

async function printSentence() {
  console.log("Hello World");
  await delay(2000); // пауза 2000 мс
  console.log("Will be printed after 2 seconds");
}

printSentence();

Вы получите последовательный вывод, при этом другие асинхронные операции в программе не будут заблокированы.

Плюсы async/await:

  • Понятный, линейный контроль потока.
  • Нет блокировки Event Loop.
  • Хорошо сочетается с промисами и современным кодом.

Ограничение: await можно применять только внутри async-функции.

Пакет sleep-promise

sleep-promise — лёгкая библиотека, которая возвращает промис и упрощает код задержек.

Установка:

npm install sleep-promise

Использование:

const sleep = require('sleep-promise');

(async () => {
  console.log("Hello World.");
  await sleep(2000); // 2 секунды
  console.log("Will be printed after two seconds.");
})();

Пакет полезен, если вы хотите минимизировать собственный код и сразу получить удобную функцию sleep.

Когда какой подход выбирать

  • Нужна минимальная задержка без ожидания порядка выполнения — setTimeout.
  • Нужен чистый последовательный код без глобальной блокировки — async/await с промисом (рекомендуется для большинства случаев).
  • Хочется максимально компактного синтаксиса — sleep-promise.
  • Нужна именно блокировка потока (редко) — используйте рабочие потоки (worker threads) или Atomics.wait в соответствующем контексте, но это выходит за рамки простых задержек.

Примеры, когда подходы дают сбой или не подходят

  • Реaltime-система с жёсткими требованиями к задержке: JavaScript и Event Loop не гарантируют детерминированную миллисекундную точность.
  • Встроенные циклы или тяжёлая синхронная работа в основном потоке отложит выполнение setTimeout.
  • Busy-wait разрушает отзывчивость сервера и приводит к потере пропускной способности — не используйте в основном процессе.

Практическое руководство: чек-листы

Для разработчика:

  • Определите, нужна ли блокировка потока.
  • Если нет — используйте async/await или sleep-promise.
  • Покройте задержки тестами, учитывая возможные задержки в окружении CI.

Для тестировщика:

  • Тестируйте сценарии с тайм-аутами на нестабильной нагрузке.
  • Убедитесь, что тесты не полагаются на точное время выполнения, а проверяют порядок событий.

Для DevOps:

  • Избегайте busy-wait в контейнерах и на узлах с ограниченным CPU.
  • Логируйте длительные задержки и пиковые нагрузки.

Критерии приёмки

  • Код не блокирует основной поток без крайней необходимости.
  • Поведение задержки покрыто тестами, допускающими небольшие вариации времени.
  • В продакшне используется корректный инструмент: async/await или sleep-promise, если нужен читаемый код.

Быстрый справочник (ключевые числа и соответствия)

  • 1000 мс = 1 с
  • setTimeout(fn, 0) — планирует выполнение как можно скорее после освобождения стека
  • Блокирующий delay через цикл — быстро расходует CPU

Простая методология выбора

  1. Нужна ли точная блокировка? Если да — используйте воркеры или низкоуровневые механизмы.
  2. Нужен порядок и читаемость — async/await.
  3. Нужна краткая запись без собственного промиса — sleep-promise.
  4. Только одно событие должно выполниться позже — setTimeout.

Визуальная подсказка (decision flow)

flowchart TD
  A[Нужно приостановить код?] --> B{Требует блокировку потока?}
  B -- Да --> C[Рассмотрите воркеры / Atomics.wait]
  B -- Нет --> D{Нужна читабельность последовательного кода?}
  D -- Да --> E[Используйте async/await + Promise]
  D -- Нет --> F{Хотите минимальный код?}
  F -- Да --> G[Используйте sleep-promise]
  F -- Нет --> H[Используйте setTimeout]

Краткое резюме

  • setTimeout хорош для простых отложенных вызовов, но не блокирует порядок выполнения.
  • async/await с промисом даёт удобную, неблокирующую паузу в последовательном коде.
  • sleep-promise экономит время на написании обвязки и даёт чистый синтаксис.

Важно: не блокируйте Event Loop в основном процессе без крайней необходимости.

Заметки:

  • Для высокоточных таймингов и realtime-задач JavaScript не подходит как основной инструмент.
  • Для блокирующего поведения используйте воркеры или платформенные механизмы.
Поделиться: X/Twitter Facebook LinkedIn Telegram
Автор
Редакция

Похожие материалы

Несколько аккаунтов Skype: Multi Skype Launcher
Программное обеспечение

Несколько аккаунтов Skype: Multi Skype Launcher

Журнал для работы: повысить продуктивность
Productivity

Журнал для работы: повысить продуктивность

Персональные звуки уведомлений на Android
Android.

Персональные звуки уведомлений на Android

Скачивание шоу Hulu для офлайн‑просмотра
Стриминг

Скачивание шоу Hulu для офлайн‑просмотра

Microsoft Start: персонализированная новостная лента
Новости

Microsoft Start: персонализированная новостная лента

Как изменить имя в Epic Games быстро
Гайды

Как изменить имя в Epic Games быстро