Alters

Timer.js: Desarrollo del Timer

 Buenas!

Y otra entrada más... ¡qué locura!

Bueno, siguiendo con el temario, hoy vamos a ver los puntos 2 y 3 de nuestro índice...

2. Problemas de apilamiento
   2.1  Do(n), pause(n)
   2.2. Do, pause, Do
3. Timer vs. setInterval
   3.1. Callback con parámetros

¿Ready? ¡Vamos allá!




El primer problema (y el que originó todo esto) viene por un problema con el apilamiento de eventos en JavaScript  cuando usamos la función de pausa "setTimeout()".

En un entorno en el que queremos que se repita una acción n veces, esperando t milisegundos cada vez, se define (de manera incorrecta) en JavaScript:

Get Raw
0001for(i=0;i<n;i++){
0002  setInterval(t, funcion);
0003}

Viendo esto, uno puede pensar que puede funcionar, pero... ¡NO! Realmente se están apilando todas las ejecuciones de funcion().

Es decir, se genera un error de concepto.

Lo que pasa realmente es la siguiente secuencia:

 - Aplazamos t milisegundos la ejecución
 - Comprobamos la validación del bucle
 - Aplazamos t milisegundos la ejecución
 ...

Al final, hemos aplazado TODO el bloque de ejecuciones t milisegundos; es decir, como dice el punto 2.1: Do(n), pause(n).

¿Cómo se solucióna?

Hay varias maneras. se puede redirigir el flujo (fue la opción que tomé yo), se puede recalcular el tiempo a cada ejecución... pero al final, necesitamos que nuestro algoritmo haga lo siguiente:

 - Aplazamos t/2 milisegundos la ejecución
 - Esperamos t/2 milisegundos
 - Comprobamos la validación del bucle

Como se puede observar, entre una ejecución y otra esperamos un tiempo, que va haciendo de "separación" entre ejecuciones, obteniendo así un verdadero efecto de temporizador (Do, pause, Do).

Obviamente este método tiene un efecto secundario, y es que no podemos usar tiempos impares (pero, a fin de cuentas ¿A quíen le importa un milisegundo?).

Otra manera (que conlleva otro tipo de limitaciones) es recalcular la espera a cada vuelta, es decir:

 - Aplazamos t * i milisegundos la ejecución
 - Comprobamos la validación del bucle (incrementando i)
 - Aplazamos t * i milisegundos la ejecución
 ...

Pero como comentaba, nosotros usaremos un modelo de flujo partido.

Y con este concepto, vamos a montar un primer esqueleto de nuestro timer:

Get Raw
0001sleep = function(){
0002  setTimeout(r_sleep, m);
0003}
0004 
0005r_sleep = function(){
0006  onTick();
0007  setTimeout(sleep, m);
0008}

donde "ontick()" es nuestra función (que se puede asignar dinámicamente), y "m" son los milisegundos/2 de espera

Con esto finalizamos el punto 2, pero entramos de lleno en el tercero...

¿Qué me dices de la función "setInterval()"?

Sí, existe una función que hace exactamente lo mismo que he escrito arriba, se llama setInterval, y funciona tal que:

setInterval(funcion, tiempo)

Y llama a "funcion" cada "tiempo" milisegundos de manera indefinida.

La principal justificación para usar nuestro método es el valor añadido, cosa que vamos a dedicar un par de entradas.

El primer punto para poder añadir valor a nuestro Timer, es poder pasar parámetros (definidos por el creador de la función de callback) a nuestra función de callback, es decir:


Get Raw
0000
0001sleep = function(){
0002    setTimeout(r_sleep, m);
0003}
0004
0005r_sleep = function(){
0006    onTick();
0007    setTimeout(sleep, m);
0008}
0009
0010onTick = function(params){
0011    //aquí podríamos usar "params" como un array que tuviera, por ejemplo, 
0012    //el ID de varios elementos a modificar
0013}


Para ello, haremos un simple truco de magia, englobando todo esto en un objeto (Timer), de manera que tengamos un contexto propio:

Get Raw
0001function Timer(milis, params, onTick){
0002    this.m = milis;
0003    this.p = params;
0004    this.onTick = onTick;
0005}
0006 
0007Timer.prototype.sleep = function(){
0008    setTimeout(this.r_sleep, this.m);
0009}
0010 
0011Timer.prototype.r_sleep = function(){
0012    this.onTick(this.p);
0013    setTimeout(this.sleep, this.m);
0014}

De manera que podamos hacer un objeto al que le pasemos un array p de parámetros que llegará a onTick y podremos usar a nuestro antojo. Todo correcto, ¿no?

¡PUES NO!

Si hacéis esto veréis que no funciona... para solucionarlo tendréis que esperar a la próxima entrada ;-)

¡Nos vemos!

No hay comentarios:

Publicar un comentario