#javascript #loops #delay
#javascript #циклы #задержка
Вопрос:
Я пытаюсь создать очень простой обратный отсчет. Когда кто-то нажимает «Выбрать случайного победителя», он выполняет selectWinner().
Я пытался выяснить, как выполнить цикл с небольшой задержкой между 3,2,1. По какой-то причине, независимо от того, куда я помещаю setTimeout или setInterval, он продолжает выполнять его ПОСЛЕ всего цикла.
Какие-нибудь советы?
// Picking name from sorting hat
const randomNumber = function () {
winningNumber = Math.trunc(Math.random() * winners.length) 1;
}
function selectWinner() {
for (let i = 3; i < 4; i--) {
if (i == 0) {
return;
} else {
setInterval(() => console.log(i), 500);
}
}
}
Ответ №1:
Происходит то, что каждый раз, когда вы вызываете setTimeout / setInterval, он ставит в очередь что-то, что должно произойти после задержки. Но ваш основной код продолжает выполняться.
например
console.log(1)
setTimeout(() => console.log(2), 100)
console.log(3)
Это выведет 1, затем 3, а после задержки будет выведено 2. Javascript не останавливает все, чтобы дождаться выполнения setTimeout, он продолжает выполнять другие задачи.
Есть несколько способов добиться того, что вы пытаетесь сделать. Самым простым вариантом (который я бы порекомендовал вам) было бы просто не иметь цикла for — вместо этого ваш setInterval будет действовать как ваш цикл for (то есть, пусть интервал выполняет цикл за вас). Вот рабочий пример:
function countdown() {
let i = 4
const interval = setInterval(() => {
i--;
console.log(i)
if (i === 0) {
clearInterval(interval)
}
}, 500)
}
countdown()
Здесь происходит то, что функция интервала будет вызываться повторно (каждые 500 мс). Каждый раз, когда он вызывается, он уменьшает значение i и регистрирует его. Как только i достигает 0, вызывается clearInterval, чтобы остановить повторение.
Для тех, кто знаком с async / await, вы можете просто дождаться тайм-аута, чтобы сохранить цикл for .
const sleep = timeout => new Promise(resolve => setTimeout(resolve, timeout))
async function countdown() {
for (let i = 3; i >= 0; i--) {
console.log(i)
await sleep(500)
}
}
countdown()
Ответ №2:
Проблемы с вашим подходом:
for
или любой другой механизм цикла синхронизируется и не будет ждать.setInterval
будет запускать функцию при каждом тике. Поэтому, если вы добавляете его на каждой итерации, вы добавляете несколько интервалов.- При каждом использовании
setInterval
принимайте ссылку на таймер, чтобы вы могли закрыть его в будущем, если потребуется
Вы можете попробовать этот подход:
- Вместо этого используйте рекурсию для создания цикла.
- Поскольку у вас есть контроль над тем, когда вызывать функцию, вы можете добавить задержку здесь
Пример использования setTimeout
let count = 3
function showCoundown() {
if (count) {
setTimeout(() => {
console.log(count--);
showCoundown();
}, 1000)
} else {
setTimeout(() => {
console.log('Winner is ...')
}, 1000)
}
}
showCoundown();
Пример использования setInterval
let count = 3
function showCoundown(count) {
if (count === 0) {
console.log('Winner is ...');
} else {
console.log(count)
}
}
function createInterval() {
let interval = setInterval(() => {
showCoundown(count--);
if (count < 0) {
window.clearInterval(interval);
interval = null;
}
}, 1000)
}
createInterval();
Ответ №3:
Это то, чего вы хотите?
function selectWinner() {
for (let i = 3, x = 1; i >= 0; i--, x ) {
setTimeout(() => {
if (i !== 0) {
console.log(i);
} else {
console.log('and the winner is...');
}
}, 500 * x)
}
}
Комментарии:
1. Жаль. Я не заметил, что это setInterval. Я это исправил.
2. Он все равно не будет работать должным образом. Пожалуйста, обратите
<>
внимание на значок в редакторе. Вы можете создать фрагмент, используя его. Кроме того, это то, чего вы хотите? это не объяснение. Пожалуйста, объясните, что и почему вы изменили3. Кроме того, не нужно ни перед кем извиняться. Мы все совершаем ошибки