Многие языки программирования имеют sleep
Функция, которая может задержать выполнение программы на несколько секунд. В JavaScript отсутствует эта встроенная функциональность, но не волнуйтесь. В этой статье мы рассмотрим различные методы реализации задержек в коде JavaScript с учетом асинхронной природы языка.
У нас также есть простые и понятные решения для тех, кому просто нужно быстрое решение проблемы, не вдаваясь в технические детали. Вот как добавить его в свой набор инструментов JavaScript. sleep
Самый прямой способ работы:
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
console.log('Hello');
sleep(2000).then(() => { console.log('World!'); });
Запустите этот код, и вы увидите «Hello» в консоли. Затем, через две секунды, появится надпись «World!» v. Это краткий и эффективный способ ввести задержку.
Если вы здесь только ради этого, это здорово! Но если вам интересно «почему» и «как», вам есть чему поучиться. В JavaScript существуют тонкости обработки времени, и, возможно, будет полезно их понять.
Теперь, когда у нас есть быстрое решение, давайте углубимся в механику модели выполнения JavaScript. Понимание этого имеет решающее значение для эффективного управления временем и асинхронными операциями в вашем коде.
Рассмотрим следующий код Ruby:
require 'net/http'
require 'json'
url = 'https://api.github.com/users/jameshibbard'
uri = URI(url)
response = JSON.parse(Net::HTTP.get(uri))
puts response['public_repos']
puts 'Hello!'
Как и следовало ожидать, этот код отправляет запрос к API GitHub для получения моих пользовательских данных. Затем он анализирует ответ, выводит количество общедоступных репозиториев, связанных с моей учетной записью GitHub, и, наконец, выводит на экран «Привет!» Исполнение происходит сверху вниз.
Для сравнения, вот версия той же функциональности на JavaScript:
fetch('https://api.github.com/users/jameshibbard')
.then(res => res.json())
.then(json => console.log(json.public_repos));
console.log('Hello!');
Если вы запустите этот код, он сначала выведет на экран «Привет!», а затем выведет количество общедоступных репозиториев, связанных с моей учетной записью GitHub.
Это связано с тем, что в JavaScript получение данных из API является асинхронной операцией. Интерпретатор JavaScript встречает команду выборки и отправляет запрос. Однако он не ждет завершения запроса. Вместо этого он продолжает выполнение, выводит на консоль «Hello!», а затем, когда запрос возвращается через несколько сотен миллисекунд, выводит количество репозиториев.
Теперь, когда мы лучше понимаем модель выполнения JavaScript, давайте посмотрим, как 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
Не блокирует выполнение остального кода.
Это означает, что вы не можете:
console.log('Hello');
setTimeout(1000);
console.log('World');
«Привет» и «Мир» сразу же записываются на консоль, без заметной задержки между ними.
Вы также не можете сделать это:
for (let i = 0; i < 5; i++) {
setTimeout(() => { console.log(i); }, i * 1000);
}
Подумайте на секунду, что может произойти с приведенным выше фрагментом кода.
Он не печатает числа с задержкой в одну секунду между каждым числом. 0
приезжать 4. Вместо этого вы фактически получите пять 4. Распечатываются все сразу через четыре секунды. Почему? Потому что цикл не приостанавливает выполнение. оно не будет ждать setTimeout
Введите следующую итерацию только после завершения.
Так что же на самом деле делает setTimeout? Теперь давайте посмотрим.
Как вы можете найти в нашем setTimeout
Учебник по чтению приезжать, собственный JavaScript setTimeout
Функция Вызывает функцию или выполняет фрагмент кода после указанной задержки (в миллисекундах).
Это может быть полезно в некоторых ситуациях, например, если вы хотите отображать всплывающее окно после того, как посетитель некоторое время просматривал вашу страницу, или если вы хотите иметь небольшую задержку перед удалением эффекта наведения с элемента (начиная с Чтобы предотвратить пользователя от случайного перемещения мыши).
setTimeout
Метод принимает ссылку на функцию в качестве первого параметра.
Это может быть имя функции:
function greet(){
alert('Howdy!');
}
setTimeout(greet, 2000);
Это может быть переменная, указывающая на функцию (функциональное выражение):
const greet = function(){
alert('Howdy!');
};
setTimeout(greet, 2000);
Или это может быть анонимная функция (в данном случае стрелочная функция):
setTimeout(() => { alert('Howdy!'); }, 2000);
Вы также можете передать строку кода в setTimeout
для его исполнения:
Однако такой подход нежелателен, поскольку:
eval
,Это потенциальная угроза безопасностикак упоминалось ранее,setTimeout
Отлично подходит для запуска одноразовых действий после задержки, но также может использоваться 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();
Это предполагает, что элемент со временем появится. Если вы не уверены, произойдет ли это, вам нужно рассмотреть возможность отмены таймера (используя clearTimeout
или clearInterval
)。
иногда,Вы можете обнаружить, что хотите внести задержки в серию операций. Хотя вы можете использовать различные методы для имитации функции сна.,Но есть еще один фактор, который часто упускают из виду.метод:Увеличить тайм-аут。
Идея проста: вместо приостановки всего потока выполнения вы используете setTimeout
Добавляйте задержку к каждой последующей операции. так,Вы можете создать последовательность отложенных операций,Без блокировки браузера и ущерба для пользовательского опыта.
Вот краткий пример:
let delay = 1000; // Старт с задержкой в 1 секунду
for (let i = 0; i < 5; i++) {
setTimeout(() => {
console.log(`Это сообщение ${i + 1}`);
}, delay);
delay += 1000; // Задержка каждой итерации увеличивается на 1 секунду.
}
существуют В этом примере,Первое сообщение появится через 1 секунду,Второе сообщение появилось через 2 секунды,и так далее,Пятое сообщение прямого прибытия появилось через 5 секунд.
Преимущества этого подхода в том, что он неблокирует, прост в реализации и не требует знаний promises
или async/await
。Однако,Он не подходит для сложных асинхронных операций, требующих точного времени и обработки ошибок.
При написании JavaScript нам часто приходится ждать, пока что-то произойдет (например, получить данные из API), а затем отреагировать (например, обновить пользовательский интерфейс для отображения данных).
В приведенном выше примере для достижения этой цели используется анонимная функция обратного вызова, но если вам нужно ждать, пока произойдет несколько событий, синтаксис может быстро стать довольно сложным, и вы можете оказаться в аду обратного вызова.
К счастью, за последние несколько лет язык сильно изменился и теперь предоставляет нам новые конструкции, позволяющие избежать этого.
Например, используйте async await
,Мы можем переписать исходный API GitHub Код для информации:
(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
метод Получено от1970Год1луна1Количество миллисекунд, прошедших со дня,и присвоить это значение date
переменная. Затем он создает пустой currentDate
переменную, а затем введите do ... while
цикл. В цикле он неоднократно получает количество миллисекунд, прошедших с 1 января 1970 года, и присваивает это значение ранее объявленному currentDate
переменная. если бы только date
и currentDate
Если разница меньше требуемого количества миллисекунд задержки, цикл продолжится.
Миссия выполнена, да? Ну, не совсем...
Возможно, этот код — именно то, что вы ожидали, но учтите, что у него есть большой недостаток: цикл блокирует поток выполнения JavaScript и гарантирует, что никто не сможет взаимодействовать с вашей программой до ее завершения. Если вам потребуется большая задержка, вы можете даже привести к сбою всей программы.
Так что же делать?
Фактически, вы также можете комбинировать методы, изученные ранее в этой статье, чтобы сделать один менее навязчивым. sleep
метод:
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
console.log('Hello');
sleep(2000).then(() => { console.log('World!'); });
Этот код напечатает «Привет» на консоли.,подожди две секунды,Затем выведите «Мир!» существует нижний слой.,Мы используем setTimeout
Метод анализирует promise
。
Обратите внимание, что нам нужно использовать then
Обратный вызов, чтобы гарантировать задержку второго сообщения. Мы также можем добавить дополнительные функции обратного вызова в цепочку после первой функции обратного вызова.
Это возможно сделать,Но это выглядит не очень хорошо。мы можем использовать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();
Это выглядит красивее, но это означает использование sleep
Любой код функции должен быть помечен как async
。
конечно,Оба типа метода все же имеют один недостаток (или особенность),То есть они не останавливают выполнение всей программы. Только ваша функция будет спать:
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function delayedGreeting() {
console.log('Hello');
await sleep(2000); // await только приостанавливает текущую асинхронную функцию
console.log('World!');
}
delayedGreeting();
console.log('Goodbye!');
Приведенный выше код выведет:
Hello
Goodbye!
World!
Таким образом, вы можете гибко использовать различные технологии методов для реализации отложенных и асинхронных операций в JavaScript в соответствии с вашими потребностями.
Мы исследовали различные способы введения задержек в JavaScript. Теперь давайте посмотрим, какой метод лучше всего подходит для различных сценариев и какого метода обычно следует избегать.
console.log('Hello');
setTimeout(() => { console.log('World!'); }, 2000);
👍 Достоинства: понятный, неблокирующий. 👎 Недостатки: Ограниченный контроль над асинхронными операциями. 📝 Когда использовать: для простых одноразовых задержек.,или Базовый опрос。
setTimeout(() => { console.log('Hello'); }, 1000);
setTimeout(() => { console.log('World!'); }, 2000);
👍 Преимущества: неблокируется, прост в реализации, не требует знаний. promises
или async/await
。
👎 Недостатки: Не подходит для сложных асинхронных операций. Обработка ошибок отсутствует.
📝 Когда использовать: для простых последовательностей с временными интервалами.
console.log('Hello');
const date = Date.now();
let currentDate = null;
do {
currentDate = Date.now();
} while (currentDate - date < 2000);
console.log('World!');
👍 Преимущества: Имитирует традиционное поведение во время сна. 👎 Недостатки: Блокировка всего потока может привести к зависанию пользовательского интерфейса и сбою программы. ⚠️ Настоятельно не рекомендуется: используйте его только в том случае, если вам абсолютно необходимо приостановить выполнение и вы осознаете связанные с этим риски.
const sleep = function(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
console.log('Hello');
sleep(2000).then(() => { console.log('World!'); });
👍 Преимущества: отсутствие блокировки, больший контроль над асинхронными операциями. 👎 Недостатки: Требует понимания обещаний. Более длинные цепочки обещаний могут немного запутать. 📝 когда использовать:Когда вам нужно больше времении Время управления асинхронной работой。
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();
👍 Достоинства: понятный синтаксис, легко читается, неблокируется. 👎 Недостатки: Необходимость понимать async/awaitиpromises. Требуется наличие внешней функции «обертки». ✅ Настоятельно рекомендуется: это самый современный и чистый метод, особенно когда существует обработка нескольких асинхронных операций.
Проблемы синхронизации в JavaScript являются источником головной боли для многих разработчиков, и то, как вы с ними справляетесь, зависит от того, чего вы хотите достичь.
Хотя встречается во многих других языках sleep
функций, но я призываю вас принять асинхронную природу JavaScript и стараться не бороться с языком. Когда привыкаешь, это на самом деле очень хорошо.