Многие языки программирования имеют функцию sleep, которая задержит выполнение программы на заданное количество секунд. Эта функциональность отсутствует в JavaScript, в силу его асинхронной природы. В этой статье мы кратко рассмотрим, как мы можем реализовать функцию sleep в JavaScript.
Скачать исходники для статьи можно ниже
Стандартный способ создания задержки в JavaScript заключается в использовании его метода setTimeout:
console.log("Hello"); setTimeout(() => { console.log("World!"); }, 2000);
Результатом данного кода будет вывод слова “Hello”, а затем через две секунды слова “World!” И во многих случаях этого достаточно: делай что-то, жди, потом делай что-то еще.
Однако имейте в виду, что setTimeout – это асинхронный метод. Попробуйте изменить предыдущий код вот так:
console.log("Hello"); setTimeout(() => { console.log("World!"); }, 2000); console.log("Goodbye!");
Результат будет следующий:
Hello
Goodbye!
World!
Также можно использовать метод setTimeout (или его двоюродного брата setInterval), чтобы заставить JavaScript ждать, пока не будет выполнено условие. Например, вот как можно использовать setTimeout ожидание появления определенного элемента на веб-странице:
function pollDOM () { const el = document.querySelector('my-element'); if (el.length) { // Do something with el } else { setTimeout(pollDOM, 300); // try again in 300 milliseconds } } pollDOM();
Это предполагает, что элемент появится в какой-то определенный момент времени. Если вы не уверены, что это произойдет, вам нужно будет изучить отмену таймера (с помощью методов clearTimeoutor, clearInterval).
Управление потоком в современном JavaScript:
Часто бывает так, что при написании JavaScript нам нужно подождать, пока что-то произойдет (например, данные будут извлечены из API), а затем сделать что-то в ответ (например, обновить пользовательский интерфейс для отображения данных).
К счастью, язык JavaScript значительно эволюционировал за последние несколько лет и теперь предлагает нам новые конструкции, например, с помощью async await мы можем заставить JavaScript выполнять код сверху вниз:
(async () => { const res = await fetch(`https://api.github.com/users/jameshibbard`); const json = await res.json(); console.log(json.public_repos); console.log("Hello!"); })();
Здесь интерпретатор JavaScript ожидает завершения сетевого запроса, и сначала регистрируется количество публичных репозиций, а затем выводит сообщение “Hello!”.
С помощью цикла заставляем JavaScript ждать!
Рассмотрим следующий код:
function sleep(milliseconds) { const date = Date.now(); let currentDate = null; do { currentDate = Date.now(); } while (currentDate - date < milliseconds); } console.log("Hello"); sleep(2000); console.log("World!");
Как и ожидалось, сначала будет выведено сообщение “Hello”, затем пауза в течение двух секунд, а после сообщение “World!”.
Вышеуказанный код использует метод Date.now для получения количества миллисекунд, прошедших с 1 января 1970 года и присваивает это значение переменной date. Затем он создает пустую currentDate переменную, прежде чем войти в do … while цикл. В цикле он повторно получает количество миллисекунд, прошедших с 1 января 1970 года, и присваивает значение ранее объявленной currentDate переменной. Цикл будет продолжать до тех пор, пока разница между date и currentDate меньше, чем требуемая задержка в миллисекундах.
Самый лучший способ создать задержку в JavaScript:
Предыдущий способ имеет большой недостаток: цикл блокирует поток выполнения JavaScript и гарантирует, что никто не сможет взаимодействовать с вашей программой до ее завершения. Если вам нужна большая задержка, есть шанс, что он даже может всё сломать.
Так что же делать?
Ну, так можно объединить методы, изученные ранее в этой статье, чтобы сделать менее навязчивую функцию сна:
function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } console.log("Hello"); sleep(2000).then(() => { console.log("World!"); });
Этот код будет выводить “Hello”, далее ждать две секунды, а затем выводить “World!” – здесь мы использовали метод setTimeout.
Обратите внимание, что в данном коде мы использовали – then – обратный вызов, чтобы убедиться, что второе сообщение регистрируется с задержкой. Мы также можем подключить больше обратных вызовов к первому сообщению:
console.log("Hello"); sleep(2000) .then(() => { console.log("World!"); }) .then(() => { sleep(2000) .then(() => { console.log("Goodbye!"); }) });
Этот код работает, но выглядит некрасиво, но если мы воспользуемся конструкцией async … await, то код станет намного лучше:
function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } async function delayedGreeting() { console.log("Hello"); await sleep(2000); console.log("World!"); await sleep(2000); console.log("Goodbye!"); } delayedGreeting();
Конечно, оба последних способа имеют свои недостатки (или особенности), например, в последнем способе, если записать код так:
function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } async function delayedGreeting() { console.log("Hello"); await sleep(2000); console.log("World!"); } delayedGreeting(); console.log("Goodbye!");
Результат будет следующий:
Hello
Goodbye!
World!
То есть в данном способе спит только функция.
PS: Вот, например, можно создать вот такой код, который записываем в файл functions.php темы wordpress:
add_action( 'wp_head', function () { ?> 1 1 1 <p id="hello">2222</p> <script> function sleep(ms) { return new Promise( resolve => setTimeout(resolve, ms) ); } async function delayedGreeting() { document.getElementById("hello").innerHTML = "С Новым Годом!"; await sleep(2000); document.getElementById("hello").innerHTML = "<div class=\"example\" style=\"color:green\">С 2020 годом!</div>"; await sleep(2000); document.getElementById("hello").innerHTML = "<img class=\"alignnone size-full wp-image-49\" src=\"https://mnogoblog.ru/wp-content/uploads/2014/12/newyeargif.png\" />"; } delayedGreeting(); </script> <?php } );
Код будет выводить сверху сайта поздравление “С Новым Годом!”, далее через 2 секунды поздравление “С 2020 годом!”, а ещё через 2 секунды покажет картинку на новогоднюю тему!
Например, чтобы по истечению