javascript settimeout loop
setTimeout no funciona dentro de forEach (2)
Lo que dijo Jason es totalmente correcto en su respuesta, pero pensé que le daría una oportunidad, para aclarar mejor.
Este es en realidad un problema de cierre clásico. Típicamente se vería algo así como:
for(var i = 0; i < 10; i++){
setTimeout(function(){
console.log(i);
},i * 1000)
}
El novato esperaría que la consola muestre:
0
(0 seconds pass...)
1
(1 second passes...)
2
(etc..)
¡Pero ese no es el caso! ¡Lo que realmente verías es que el número 10
se registra 10 veces (1 vez por segundo)!
"¿Por qué sucede eso?" Gran pregunta Alcance de cierre. El bucle for
anterior no tiene alcance de cierre porque en javascript, solo las funciones (lambdas) tienen alcance de cierre.
Consulte: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures
¡Sin embargo! Tu intento hubiera logrado el resultado deseado si hubieras intentado esto:
json.objects.forEach(function(obj,index,collection) {
setTimeout(function(){
console.log(''foobar'');
self.insertDesignJsonObject(obj, index);
}, index * 5000);
});
Debido a que tiene acceso a la variable de index
"closur-ed", puede confiar en que su estado es el estado esperado cuando se invoca la función (lambda).
Otros recursos:
¿Cómo funcionan los cierres de JavaScript?
http://javascript.info/tutorial/closures
http://code.tutsplus.com/tutorials/closures-front-to-back--net-24869
Tengo un forEach que llama a una función. Tiene que haber un retraso entre cada vez que se llama. Lo puse dentro de un setTimeout dentro del forEach. No se respeta el tiempo de espera después de la primera espera. En lugar de eso, está esperando una vez, luego corriendo todo a la vez. He establecido el tiempo de espera en 5 segundos y estoy usando una consola para confirmar. 5 segundos de espera, luego varios registros de consola foobar a la vez.
¿Por qué estoy teniendo este comportamiento?
var index = 0;
json.objects.forEach(function(obj) {
setTimeout(function(){
console.log(''foobar'');
self.insertDesignJsonObject(obj, index);
}, 5000);
});
setTimeout es aync. Lo que hace es registrar una función de devolución de llamada y ponerla en segundo plano que se activará después de la demora. Mientras que forEach es una función síncrona. Entonces, lo que hizo su código es registrar las devoluciones de llamada "todas a la vez" que cada una se activará después de 5 segundos.
Dos formas de evitarlo:
Tener un índice para configurar el temporizador.
json.objects.forEach(function(obj, index) {
setTimeout(function(){
// do whatever
}, 5000 * (index + 1));
});
De esta manera, el factor de retraso se basa en el índice de sus objetos, por lo que incluso si los registra al mismo tiempo, se activará en función de su propio retraso. index + 1
para mantener el mismo resultado que en cuestión, ya que comienza en 0.
setInterval para enlazar tus objetos
var i = 0;
var interval = setInterval(function(){
var obj = json.objects[i];
// do whatever
i++;
if(i === json.objects.length) clearInterval(interval);
}, 5000);
setInterval es similar a setTimeout, aunque se dispara periódicamente en función del intervalo. Aquí accedemos al objeto y actualizamos el índice dentro de la función de intervalo. Además, no se olvide de borrar el intervalo al final.
La diferencia entre esos dos es que setInterval solo registra una función en comparación con setTimeout registrado hasta el número de elementos en la lista.