2011-10-13 32 views
24

Estoy tratando de ejecutar múltiples temporizadores dada una lista variable de elementos. El código es como la siguiente:Cómo utilizar la función setInterval dentro del ciclo for

var list = Array(...); 

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

El problema con el código anterior es que el único valor que se actualiza es el elemento al final de la lista, multiplicado por el número de elementos de la lista.

¿Alguien puede ofrecer una solución y una explicación así que sé por qué se está comportando de esta manera?

Respuesta

32

Así, un par de cosas:

  1. que es más importante, la función de devolución de llamada que haya pasado a setInterval() mantiene una referencia a x en lugar del valor instantánea de x tal como existía durante cada iteración en particular. Entonces, como x se cambia en el ciclo, también se actualiza dentro de cada una de las funciones de devolución de llamada.
  2. Además, for...in se utiliza para enumerar las propiedades del objeto y puede behave unexpectedly cuando se utiliza en matrices.
  3. Además, sospecho que realmente quiere setTimeout() en lugar de setInterval().

Puede pasar argumentos a la función de devolución de llamada mediante el suministro de argumentos adicionales para setTimout():

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

He aquí un ejemplo:

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 
 
}

Por suerte, los números van pasando por valor en lugar de referencia.

+0

Sí, podría recomendar leer este artículo: http://blog.morrisjohns.com/javascript_closures_for_dummies. Además de eso, setTimeout dentro de un bucle puede no ser lo que él quiere hacer de todos modos, ya que todas las devoluciones de llamadas se dispararán al mismo tiempo, no se escalonarán. – SoWeLie

+0

El OP no "necesita un cierre", sino todo lo contrario: tiene un cierre a * x * que debe evitarse (lo que realmente hace su respuesta). Sin embargo, mantiene el cierre a * list *. – RobG

33

Aquí está el código de trabajo:

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

Aquí el índice i se almacena en una función anónima, de modo que no se sobrescribe con bucles consecutivos. La función setInterval en su código mantiene la referencia solo al último valor de i.

+0

¡buena solución! –

+0

¡Excelente solución! Una pequeña nota: cualquier cosa que se pueda cambiar en el ciclo se puede pasar a la función anónima, no solo al índice. –

2

No es necesario utilizar un ciclo para con la instrucción setInterval. Prueba esto:

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

Si tiene matriz JSON y jQuery incluido, puede utilizar:

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

No sé cómo hacer esto con un bucle, pero este código aquí se imprimirá cada elemento de una matriz a intervalos de tiempo:

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

el uso de un poco de jquery para mostrar en el navegador.

Cuestiones relacionadas