Avatar ·

Как сделать паузу (sleep) в JavaScript? Нужен аналог sleep() из других языков

Всем привет! Я новичок в JavaScript, перешел с Python, и столкнулся с проблемой. В Python я часто использовал `time.sleep(2)`, чтобы поставить выполнение программы на паузу, например, при работе с API, чтобы не превысить лимит запросов, или при анимациях в консоли. В JavaScript я попробовал написать что-то похожее: ```javascript function sleep(ms) { // ????? } console.log("Начинаем"); sleep(2000); console.log("Прошло 2 секунды"); ``` Но я не могу найти встроенную функцию `sleep()`. Я пробовал использовать `setTimeout`, но он не останавливает выполнение кода, а просто откладывает вызов колбэка. В итоге сообщение "Прошло 2 секунды" выводится сразу, а не через 2 секунды. Подскажите, как правильно реализовать задержку в JavaScript? Мне нужно, чтобы код выполнялся последовательно: сначала вывелось "Начинаем", потом была пауза в 2 секунды, и только потом вывелось "Прошло 2 секунды". Желательно, чтобы решение было современным и работало в браузере и Node.js. Заранее спасибо! <<>>

Проблема: JavaScript — асинхронный по своей природе

В отличие от Python или PHP, JavaScript (особенно в браузере) не блокирует поток выполнения. Функции вроде setTimeout или setInterval не останавливают код, а ставят задачу в очередь событий. Поэтому ваш код выполняется мгновенно.

Современное решение: промисы и async/await

Начиная с ES2017, в JavaScript появилась конструкция async/await, которая позволяет писать асинхронный код так, как будто он синхронный. Вам нужно создать функцию, которая возвращает промис, разрешающийся через заданное количество миллисекунд.

function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

// Использование с async/await
async function main() {
  console.log("Начинаем");
  await sleep(2000); // Ждём 2 секунды
  console.log("Прошло 2 секунды");
}

main();

Как это работает

  • new Promise(resolve => setTimeout(resolve, ms)) — создаёт промис, который "разрешится" (вызовет resolve) через ms миллисекунд.
  • await приостанавливает выполнение асинхронной функции до тех пор, пока промис не будет разрешён.
  • Функция main должна быть объявлена как async, чтобы внутри неё можно было использовать await.

Альтернатива: синхронный sleep (НЕ РЕКОМЕНДУЕТСЯ)

В Node.js есть синхронная функция Atomics.wait() или утилита sleep из пакета timers/promises (с Node 15+), но она блокирует главный поток. В браузере синхронного sleep нет, и его не стоит делать, так как это заморозит интерфейс.

// Node.js (только для скриптов, не для серверов!)
const { setTimeout } = require('timers/promises');

async function main() {
  console.log("Начинаем");
  await setTimeout(2000);
  console.log("Прошло 2 секунды");
}

Практический пример: повтор с задержкой

Часто sleep используют в циклах, например, для опроса сервера:

async function pollServer() {
  for (let i = 0; i < 5; i++) {
    console.log(`Попытка ${i + 1}`);
    // Здесь мог быть fetch()
    await sleep(1000); // Ждём 1 секунду между попытками
  }
  console.log("Опрос завершён");
}

Важные замечания

  • await работает только внутри async функций.
  • Не пытайтесь сделать sleep с помощью циклов while(Date.now() < deadline) — это заблокирует процесс и может повесить браузер.
  • В современных проектах используйте import { setTimeout } from 'timers/promises' (Node.js) или обёртку с Promise (универсально).

Итог: правильный способ сделать паузу в JavaScript — это комбинация Promise + setTimeout + async/await. Это не блокирует поток и работает везде.

<<>>

Альтернативный подход: sleep без async/await (только промисы)

Если вы не можете использовать async/await (например, работаете со старым кодом или в среде без поддержки ES2017), можно использовать цепочку промисов:

function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

console.log("Начинаем");
sleep(2000).then(() => {
  console.log("Прошло 2 секунды");
});

Этот код делает то же самое, но без async. Метод .then() выполнится только после того, как промис разрешится через 2 секунды.

Дополнение: утилита для повторяющихся действий

Вы можете создать обёртку для выполнения задачи с задержкой после каждого вызова:

function withDelay(fn, ms) {
  return async (...args) => {
    await sleep(ms);
    return fn(...args);
  };
}

const delayedLog = withDelay(console.log, 1000);
delayedLog("Это сообщение появится через 1 секунду");

Этот паттерн удобен для rate-limiting (ограничения частоты вызовов) при работе с API.