Un delay en Javascript
enero 16, 2009 Publicado en Software y HardwareEtiquetas: javascript
Hacer un retardo en Javascript se había convertido en un quebradero de cabeza para mí en los últimos días. Algunos algoritmos que estaba implementando requerían que su ejecución se detuviese por un lapso de tiempo para luego proseguir, pero en el caso particular de Javascript no existe un método similar a la función delay, disponible en algunos lenguajes multipropósito. Los métodos disponibles en Javascript posponen el inicio de otro proceso hasta que se cumpla un tiempo de espera, pero el proceso en ejecución continúa su curso normal.
En un lenguaje donde se acepte delay(n), un código que emplee esta función esperaría n milisegundos antes de continuar con la ejecución del proceso, pero como en Javascript no existe esta función se deberá emplear otra solución que posponga la ejecución del código.
En algunas páginas he visto que recomiendan aplicar un ciclo como mecanismo de espera, pero esta solución no es para nada práctica porque la máquina virtual al final termina dedicando su tiempo de proceso casi que exclusivamente al ciclo, descuidando los demás procesos en ejecución. No es una buena idea codificar una solución de este tipo cuando se está trabajando en un proyecto que implementa llamados asíncronos, como por ejemplo una página con tecnología Ajax.
La solución que identifiqué para la situación de los retardos en Javascript la diseñé mientras analizaba cómo implementar la técnica de semáforos en el plugin minimax. En un momento del proceso el sistema indaga por el estado del semáforo, y en caso de estar en verde ejecutaría el código, pero si está en rojo activaría un temporizador que llamaría recursivamente la función al pasar el tiempo de espera.
a='Hola';
b='mundo';
setTimeout(
function() {
alert(a+' '+b);
}, 1000);
En este script, las variables dentro del llamado a setTimeout quedan desligadas de las variables de la función, es decir que será necesario cargarlas empleando alguna técnica, como por ejemplo a través de variables globales o como parámetros de una función. En este caso particular las variables fueron declaradas como globales así que el resultado será el esperado.
Para las llamadas recursivas a través de setTimeout hechas sobre una función pública (tratándose de clases) se deberá emplear un nombre propio para declarar el ámbito de la clase. El siguiente ejemplo presenta una clase que estará en un ciclo eterno esperando por una señal de semáforo para visualizar un resultado. El botón cambiará el estado del semáforo, y una vez el usuario haya aceptado la ventana emergente el semáforo retornará al estado de espera y volverá a llamar el mecanismo de espera.
<script type='text/javascript'>
//Clase que llamará recursivamente una función pública propia
function Foo() {
var me = this; //Declarando la variable de ámbito
me.sem = 0; //La variable semáforo
var text1 = 'Hola'; //Variable de texto privada
me.text2 = 'mundo'; //Variable de texto pública
me.recursiva = function() { //Función pública de la clase
if(me.sem) {
alert(text1+' '+me.text2);
me.sem=0;
me.recursiva();
} else {
setTimeout(function() { me.recursiva() }, 1000);
}
}
}
var aux = new Foo();
aux.recursiva();
</script>
<input type='button' value='Push' onclick='aux.sem=1' />
Si se hubiese empleado this en vez de la variable de ámbito de la clase que se declara al principio, la máquina virtual habría devuelto un error, porque setTimeout inicia un nuevo proceso desligado de la instancia que lo llamó, y por lo tanto this sería identificado como el nuevo proceso y no como la instancia de la clase. Como en este caso se usa la variable declarada al interior de la clase entonces la máquina virtual sabrá cuál es la instancia con base en la cual se deberá crear el nuevo proceso.
olle y como detengo la repeticion ciclica de la funcion O.o?
Gracias, mi memoria me estaba fallando con respecto a esta función.
Muchas gracias por la idea, me ha servido mucho, estaba tan bloqueado con esto del delay en javascript que no atinaba a nada, «la recursividad es la recursividad», por mi parte hice algo mas sencillo, una pequeña función muy simple que se llama a sí misma n cantidad de veces, debo admitir que estaba tan jodido por otro problemillas con JQuery y AJAX que ni siquiera pensé que funcionara a la primera, y… FUNCIONO!!! De nuevo GRACIAS
mi pequeña pero efectiva función
function delay(seconds)
{
if (seconds> 0)
{
setInterval(delay(seconds- 1), 1000);
}
}