2011-10-13 30 views
24

Próbuję uruchomić wiele timerów, biorąc pod uwagę listę zmiennych elementów. Kod wygląda mniej więcej tak:Jak korzystać z funkcji setInterval wewnątrz pętli for

var list = Array(...); 

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

Problem z powyższego kodu jest to, że jedyną wartością jest aktualizowany jest element na koniec listy, pomnożonej przez liczbę elementów na liście.

Czy ktoś może zaoferować rozwiązanie i pewne wyjaśnienie, więc wiem, dlaczego zachowuje się w ten sposób?

Odpowiedz

32

Tak, kilka rzeczy:

  1. Najważniejsze, że funkcja zwrotna przeszedłeś do setInterval() utrzymuje odniesienie do x zamiast wartości migawkę x jak to miało miejsce podczas poszczególnych iteracji. Ponieważ zmieniono w pętli x, jest ona również aktualizowana w ramach każdej z funkcji wywołania zwrotnego.
  2. Dodatkowo, for...in służy do wyliczenia właściwości obiektu i może behave unexpectedly, gdy jest używany na tablicach.
  3. Co więcej, podejrzewam, że naprawdę chcesz, a nie setInterval().

można przekazywać argumenty do funkcji wywołania zwrotnego poprzez dostarczenie dodatkowych argumentów setTimout():

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

Oto przykład:

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 
 
}

szczęście numery przejdzie według wartości, a nie odniesienia.

+0

Tak, mogę polecić przeczytanie tego artykułu: http://blog.morrisjohns.com/javascript_closures_for_dummies. Co więcej, setTimeout w pętli może nie być tym, co chce zrobić, ponieważ wszystkie wywołania zwrotne zostaną uruchomione w tym samym czasie, nie będą rozłożone. – SoWeLie

+0

OP nie "potrzebuje zamknięcia", wręcz przeciwnie - ma zamknięcie na * x *, którego należy unikać (co faktycznie robi twoja odpowiedź). Zachowuje jednak zamknięcie na * liście *. – RobG

33

Oto kod działa:

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); 
} 

Tutaj indeks i jest przechowywany w anonimowej funkcji, tak, że nie są zastępowane przez kolejne pętle. setInterval funkcja w kodzie zachowuje odniesienie tylko do ostatniej wartości i.

+0

dobre rozwiązanie !! –

+0

Doskonałe rozwiązanie! Mała uwaga: wszystko, co można zmienić w pętli, można przekazać do anonimowej funkcji, a nie tylko do indeksu. –

2

Nie trzeba używać cyklu do wykonania z instrukcją setInterval. Spróbuj tego:

var list = Array(...); 
var x = 0; 

setInterval(function() { 

    if (x < list.length;) { 
     list[x] += 10; 
     console.log(x+"=>"+list[x]); 
    } 

    else return; 

    x++; 
}, 5000); 
0

Jeśli masz tablicę JSON i jQuery włączone, można użyć:

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

Nie wiem, jak to zrobić z pętli for ale ten kod tutaj wypisze każdy element w tablicy w określonych odstępach czasu:

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(); 

Za pomocą odrobiny jquery, aby pokazać go w przeglądarce.

Powiązane problemy