Как использовать функцию setInterval внутри цикла for - PullRequest
29 голосов
/ 13 октября 2011

Я пытаюсь запустить несколько таймеров, учитывая переменный список элементов.Код выглядит примерно так:

var list = Array(...);

for(var x in list){
    setInterval(function(){
        list[x] += 10;
        console.log(x + "=>" + list[x] + "\n");
    }, 5 * 1000);
}

Проблема с приведенным выше кодом состоит в том, что обновляется только значение в конце списка, умноженное на количество элементов в списке.

Может кто-нибудь предложить решение и какое-то объяснение, чтобы я знал, почему он так себя ведет?

Ответы [ 6 ]

39 голосов
/ 13 октября 2011

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.

38 голосов
/ 13 октября 2011

Итак, несколько вещей:

  1. Самое главное, что функция обратного вызова, которую вы передали setInterval(), поддерживает ссылку на x, а не значение снимка x, которое существовало во время каждой конкретной итерации. Таким образом, поскольку x изменяется в цикле, оно также обновляется в каждой из функций обратного вызова.
  2. Кроме того, for...in используется для перечисления свойств объекта и может вести себя неожиданно при использовании в массивах.
  3. Более того, я подозреваю, что вы действительно хотите setTimeout(), а не setInterval().

Вы можете передать аргументы в функцию обратного вызова, предоставив дополнительные аргументы для setTimout():

var timeoutID = window.setTimeout(func, delay<b>, [param1, param2, ...]</b>);

Числа будут передаваться по значению, а не по ссылке. Вот пример:

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
}
4 голосов
/ 12 сентября 2013

Вам не нужно использовать цикл for с оператором 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);
2 голосов
/ 29 марта 2016

Я не знаю, как сделать это с помощью цикла 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, чтобы показать его в браузере.

0 голосов
/ 26 октября 2018

Вы можете объединить 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)
})
0 голосов
/ 04 декабря 2014

Если у вас есть массив JSON и jQuery, вы можете использовать:

$.each(jsonArray, function(i, obj) {
    setInterval( function() {
        console.log(i+' '+obj);
    }, 10);
});
...