Как использовать функцию setInterval внутри цикла for
Я пытаюсь запустить несколько таймеров, учитывая переменный список элементов. Код выглядит примерно так:
var list = Array(...);
for(var x in list){
setInterval(function(){
list[x] += 10;
console.log(x + "=>" + list[x] + "\n");
}, 5 * 1000);
}
Проблема с приведенным выше кодом состоит в том, что единственное обновляемое значение - это элемент в конце списка, умноженный на количество элементов в списке.
Может кто-нибудь предложить решение и какое-то объяснение, чтобы я знал, почему он так себя ведет?
7 ответов
Итак, несколько вещей:
- Самое главное, функция обратного вызова, которую вы передали
setInterval()
поддерживает ссылку наx
а не значение снимкаx
как это существовало во время каждой конкретной итерации. Таким образомx
изменяется в цикле, он также обновляется в каждой из функций обратного вызова. - Дополнительно,
for...in
используется для перечисления свойств объекта и может вести себя неожиданно при использовании в массивах. - Более того, я подозреваю, что вы действительно хотите
setTimeout()
скорее, чемsetInterval()
,
Вы можете передать аргументы в функцию обратного вызова, предоставив дополнительные аргументы setTimout()
:
var timeoutID = window.setTimeout(func, delay, [param1, param2, ...]);
Вот пример:
var list = [1,2,3,4];
for (var x = 0, ln = list.length; x < ln; x++) {
setTimeout(function(y) {
console.log("%d => %d", y, list[y] += 10);
}, x * 500, x); // we're passing x
}
К счастью, числа передаются по значению, а не по ссылке.
var list = [1, 2, 3, 4, 5];
for (var i = 0, len = list.length; i < len; i += 1) {
(function(i) {
setInterval(function() {
list[i] += 10;
console.log(i + "=>" + list[i] + "\n");
}, 5000)
})(i);
}
Вот рабочий код:
var list = [1, 2, 3, 4, 5];
for (var i = 0, len = list.length; i < len; i += 1) {
(function(i) {
setInterval(function() {
list[i] += 10;
console.log(i + "=>" + list[i] + "\n");
}, 5000)
})(i);
}
Здесь индекс i
хранится в анонимной функции, поэтому она не перезаписывается последовательными циклами. setInterval
функция в вашем коде сохраняет ссылку только на последнее значение i
,
Вы можете объединить forEach
а также setTimeout
цикл по массиву с интервалом.
let modes = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let interval = 1000; //one second
modes.forEach((mode, index) => {
setTimeout(() => {
console.log(mode)
}, index * interval)
})
Вам не нужно использовать для цикла с setInterval
заявление. Попробуй это:
var list = Array(...);
var x = 0;
setInterval(function() {
if (x < list.length;) {
list[x] += 10;
console.log(x+"=>"+list[x]);
}
else return;
x++;
}, 5000);
Я не знаю, как сделать это с помощью цикла for, но этот код здесь будет распечатывать каждый элемент в массиве через определенные интервалы времени:
function displayText(str) {
$('.demo').append($('<div>').text(str));
}
var i = 0;
var a = [12, 3, 45, 6, 7, 10];
function timedLoop() {
setTimeout(function () {
displayText(a[i]);
i++;
if(i < a.length) {
timedLoop();
}
}, 2000)
}
timedLoop();
Используя немного jquery, чтобы показать это в браузере.
Пожалуйста, посмотрите на это самое простое решение. Это работает и с forloop. Это выглядит как интервал, но это тайм-аут, увеличивающийся для каждой итерации. Для каждой итерации setTimeout удваивается.
Если у вас есть массив JSON и jQuery, вы можете использовать:
$.each(jsonArray, function(i, obj) {
setInterval( function() {
console.log(i+' '+obj);
}, 10);
});