Ayuda con JS - Funcion sigue ejecutandose despues de haber terminado.

B

!!AL FINAL DEL HILO HAY UN RESUMEN DEL PROBLEMA

Estoy realizando un cronómetro tipo ‘Pomodoro’ para uso propio de mis sesiones de estudio y a su vez aprender Javascript.

Cuando el contador del trabajo y el descanso termina de ejecutar, el contador de ciclos suma uno, hasta aquí todo bien. Conseguí que cuando el contador de ciclos sume uno, el temporizador de trabajo y descanso vuelva a su estado normal. ¿El problema? que en el fondo la función temporizador() se sigue ejecutando y me salta el alert() establecido en el eventListener comenzar como que el tiempo sigue corriendo.[

Para que esté todo claro empiezo describiendo mi código (si encuentras algún error, algo no debería de estar donde está o no debería realizar ciertas prácticas dímelo qué soy principiante). Me salto los botones y los llevó directamente a los manejadores de eventos. Como el error implica únicamente un manejador se los pongo:

comenzar.addEventListener('click', function () {
    if (comenzarTiempo === undefined) {
        comenzarTiempo = setInterval(temporizador, 1000); 
    } else {
        alert('El tiempo ya esta corriendo!');
        return;
    }
})

Pues bien, este manejador cuando se le hace click al botón llama a la función temporizador [más abajo] cada segundo y guarda el valor del tiempo en la var comenzarTiempo. Esta es la función del temporizador();

//Cronometro
function temporizador() {
    //Contador de los 25minutos de trabajo.
    if (ts.innerText != 0) {
       ts.innerText--;
   } else if(tm.innerText != 0 && ts.innerText == 0) {
       ts.innerText = 59;
       tm.innerText--;
   }
  
//Contador de los 5minutos de descanso. if (tm.innerText == 0 && ts.innerText == 0) { if (ds.innerText != 0) { ds.innerText--; } else if (ds.innerText == 0 && dm.innerText != 0) { ds.innerText = 59; dm.innerText--; } }
//Contador de ciclos de trabajo. if (tm.innerText == 0 && ts.innerText == 0) { if (dm.innerText == 0 && ds.innerText == 0) { tm.innerText = 25; ts.innerText = "00"; dm.innerText = "05"; ds.innerText = "00"; contador.innerText++; } } return; } function ciclos() { clearTimeout(comenzarTiempo) detenerTiempo()
} function detenerTiempo() { clearInterval(comenzarTiempo); }

Resumen: cuando presiono un botón que llama a una función esa función al acabar en el fondo sigue ejecutándose y si vuelvo a presionar el botón para volver a ejecutar la función no puedo ya que en el fondo sigue ejecutándose.

El motivo de mi pregunta es para que el usuario pueda volver a iniciar el temporizador cuando el quiera y no automaticamente cuando se haya cumplido un ciclo.

Gracias!

isvidal

Tienes que entender comenzarTiempo solo sera undefined en la primera ejecucion. El metodo clearInterval no elimina la referencia guardada en comenzarTiempo solo elimina/cancela la ejecucion del intervalo.

Si pusieras un console.log en el eventListener con el valor de comenzarTiempo lo verias rapidamente, en las siguientes ejecuciones, el valor devuelto seria la firma de una funcion y no undefined.

Supongo que la declararas como metodo global, si quieres hacer un apa;o guarro, en detenerTiempo() aparte del clearInterval puedes hacer comenzarTiempo = undefined.

B

Cuando con una linea me solucionas el problema, me siento estupido... xd

He puesto el metodo guarro como dices tu para almenos poder usarlo ahora que he vuelto a estudiar. Lo arreglare con tu primer parrafo para hacerlo limpio pero no lo llego a entender.

Mi modelo mental de esto es que:

comenzarTiempo

es indefinido al principio lo deja de ser cuando presionas comenzar. El

clearInteral() 

cancela que la funcion

temporizador()

deje de ejecutarse pero el valor de

comenzarTiempo

ya no es indefinido, si no que como ya has llamado al evento ahora

comenzarTiempo = setInterval(temporizador, 2000);

y no puedes volver a llamar al evento porque este solo funciona si

comenzarTiempo = undefined;

.

Sinceramente no me planteo ninguna otra solucion que no sea la de establecer

comenzarTIempo = undefined;

. Lo que iba a hacer era una condicion para establecer que si el contador es diferente a 0, ponga a comenzarTiempo como undefined.

1 respuesta
isvidal

#3 Es mucho mas sencillo.

comenzarTiempo es una variable, si la declaras como var comenzarTiempo; es una variable que apunta a undefined.

Cuando tu haces comenzarTiempo = setInterval(temporizador, 2000); lo que estas haciendo es apuntar la variable comenzarTiempo, que era undefined, al valor devuelto por la ejecucion de setInterval() que en este caso sera una referencia a una funcion que a posteriori permite eliminar el intervalo.

Entonces comenzarTiempo deja de apuntar a undefined y apunta a la referencia devuelta por la ejecucion de setInterval() y por ende en las siguientes ejecuciones ya no es undefined, pues lo que limpias con clearInterval es el intervalo no estas volviendo a poner comenzarTiempo a undefined.

Lo que te esta pasando es que creo que relacionas la expresion comenzarTiempo = setInterval(temporizador, 2000); con empezar el contador, cuando relamente lo que empieza el contador es setInterval(temporizador, 2000);, no necesitas el comenzarTiempor para nada para empezar a contar. El comenzarTiempo solo sirve para almacenar la referencia al intervalo que luego se le pasa al clearInterval y que sirve para limpiarlo.

Cambia el nombre de comenzarTiempo por referenciaIntervalo y veras como todo tiene mas sentido. No estas comenzando el tiempo, estas almacenando la referencia al intervalo (Devuelta por setInterval()) que luego se usa para limpiar este mismo intervalo.

Recomendare esto por 25 vez en este foro: https://justjavascript.com/ , son tutos super cortos 5 minutos max donde Dan explica de forma muy nitida "su" modelo mental de JS y creo que te dara una imagen mucho mas clara de lo que te digo.

De todas formas no hay trampa ni carton, no te ralles por sentirte inutil y no entender algo que yo te vendo como obvio, no es por ser inteligente (No lo soy) que lo se y hubo un dia que estaba com tu o peor, pero al final de tantas ostias que te das aprendes si o si:

Always remember:

1
JuAn4k4

No es más fácil que al hacer click te guardes un timestamp de inicio? Y ejecutes un intervalo que te calcule el tiempo que llevas.

1 respuesta
B

Muchas gracias, y recuerdo que fue por ti en un hilo sobre recursos para aprender que comentaste y encontre justjavascript, ya he terminado la serie de emails de Dan. Muy utiles.


#5 Estoy siguiendo unos proyectos que ya tienen su codigo hecho para comparar y tener un punto para partir.

B

Ya he terminado :grinning:. Aqui el repositorio ( https://github.com/EzeDlr/Pomodoro-Timer ) y la demo ( https://ezedlr.github.io/Pomodoro-Timer/ )

3

Usuarios habituales