javascript - sirve - encontrar el tiempo que queda en un setTimeout()?
settimeout not working (10)
EDITAR: en realidad creo que hice una mejor: https://stackoverflow.com/a/36389263/2378102
Escribí esta función y la uso mucho:
function timer(callback, delay) {
var id, started, remaining = delay, running
this.start = function() {
running = true
started = new Date()
id = setTimeout(callback, remaining)
}
this.pause = function() {
running = false
clearTimeout(id)
remaining -= new Date() - started
}
this.getTimeLeft = function() {
if (running) {
this.pause()
this.start()
}
return remaining
}
this.getStateRunning = function() {
return running
}
this.start()
}
Hacer un temporizador:
a = new timer(function() {
// What ever
}, 3000)
Entonces, si quieres que te quede el tiempo justo, hazlo:
a.getTimeLeft()
Estoy escribiendo un Javascript que interactúa con el código de la biblioteca que no soy de mi propiedad y no puedo (razonablemente) cambiar. Crea tiempos de espera de Javascript utilizados para mostrar la siguiente pregunta en una serie de preguntas de tiempo limitado. Este no es un código real porque está ofuscado más allá de toda esperanza. Esto es lo que la biblioteca está haciendo:
....
// setup a timeout to go to the next question based on user-supplied time
var t = questionTime * 1000
test.currentTimeout = setTimeout( showNextQuestion(questions[i+1]), t );
Quiero poner una barra de progreso en pantalla que se llene hacia questionTime * 1000
al interrogar el temporizador creado por setTimeout
. El único problema es que parece que no hay forma de hacer esto. ¿Hay una función getTimeout
que me falta? La única información sobre los tiempos de espera de Javascript que puedo encontrar está relacionada solo con la creación a través de setTimeout( function, time)
y eliminación a través de clearTimeout( id )
.
Estoy buscando una función que devuelva el tiempo restante antes de que se agote el tiempo de espera o el tiempo transcurrido después de que se haya llamado a un tiempo de espera. Mi código de barras de progreso se ve así:
var timeleft = getTimeout( test.currentTimeout ); // I don''t know how to do this
var $bar = $(''.control .bar'');
while ( timeleft > 1 ) {
$bar.width(timeleft / test.defaultQuestionTime * 1000);
}
tl; dr: ¿Cómo encuentro el tiempo restante antes de un javascript setTimeout ()?
Aquí está la solución que estoy usando ahora. Pasé por la sección de la biblioteca que está a cargo de las pruebas y descifré el código (terrible y en contra de mis permisos).
// setup a timeout to go to the next question based on user-supplied time
var t = questionTime * 1000
test.currentTimeout = mySetTimeout( showNextQuestion(questions[i+1]), t );
y aquí está mi código:
// wrapper for setTimeout function mySetTimeout( func, timeout ) { timeouts[ n = setTimeout( func, timeout ) ] = { start: new Date().getTime(), end: new Date().getTime() + timeout t: timeout } return n; }
Esto funciona bastante bien en cualquier navegador que no sea IE 6. Incluso el iPhone original, donde esperaba que las cosas se volvieran asíncronas.
Esta es quizás una forma aún mejor de hacerlo, además, no necesitará cambiar el código que ya ha escrito:
var getTimeout = (function() { // IIFE
var _setTimeout = setTimeout, // Reference to the original setTimeout
map = {}; // Map of all timeouts with their start date and delay
setTimeout = function(callback, delay) { // Modify setTimeout
var id = _setTimeout(callback, delay); // Run the original, and store the id
map[id] = [Date.now(), delay]; // Store the start date and delay
return id; // Return the id
};
return function(id) { // The actual getTimeLeft function
var m = map[id]; // Find the timeout in map
// If there was no timeout with that id, return NaN, otherwise, return the time left clamped to 0
return m ? Math.max(m[1] - Date.now() + m[0], 0) : NaN;
}
})();
... Y mimetizado:
var getTimeout=function(){var e=setTimeout,b={};setTimeout=function(a,c){var d=e(a,c);b[d]=[Date.now(),c];return d};return function(a){return(a=b[a])?Math.max(a[1]-Date.now()+a[0],0):NaN}}();
La pregunta ya ha sido respondida pero agregaré mi parte. Simplemente se me ocurrió.
Use setTimeout
en la recursion
siguiente manera:
var count = -1;
function beginTimer()
{
console.log("Counting 20 seconds");
count++;
if(count <20)
{
console.log(20-count+"seconds left");
setTimeout(beginTimer,2000);
}
else
{
endTimer();
}
}
function endTimer()
{
console.log("Time is finished");
}
Supongo que el código es auto explicativo
Las pilas de eventos de Javascript no operan cómo piensas.
Cuando se crea un evento de tiempo de espera, se agrega a la cola de eventos, pero otros eventos pueden tener prioridad mientras se está disparando ese evento, retrasar el tiempo de ejecución y posponer el tiempo de ejecución.
Ejemplo: crea un tiempo de espera con un retraso de 10 segundos para alertar algo a la pantalla. Se agregará a la pila de eventos y se ejecutará después de que se activen todos los eventos actuales (lo que ocasiona cierta demora). Luego, cuando se procesa el tiempo de espera, el navegador continúa capturando otros eventos y los agrega a la pila, lo que causa más retrasos en el procesamiento. Si el usuario hace clic, o escribe mucho ctrl +, sus eventos tienen prioridad sobre la pila actual. Sus 10 segundos pueden convertirse en 15 segundos o más.
Dicho esto, hay muchas maneras de simular cuánto tiempo ha pasado. Una forma es ejecutar un setInterval justo después de agregar el setTimeout a la pila.
Ejemplo: Realice un tiempo de ajuste con un retraso de 10 segundos (almacene ese retraso en un global). A continuación, realice un setInterval que se ejecuta cada segundo para restar 1 del retraso y dar salida a la demora restante. Debido a la forma en que la pila de eventos puede influir en el tiempo real (descrito anteriormente), esto aún no será preciso, pero da un conteo.
En resumen, no hay una forma real de obtener el tiempo restante. Solo hay formas de intentar y transmitir una estimación al usuario.
No, pero puede tener su propio setTimeout / setInterval para la animación en su función.
Diga que su pregunta es así:
function myQuestion() {
// animate the progress bar for 1 sec
animate( "progressbar", 1000 );
// do the question stuff
// ...
}
Y su animación será manejada por estas 2 funciones:
function interpolate( start, end, pos ) {
return start + ( pos * (end - start) );
}
function animate( dom, interval, delay ) {
interval = interval || 1000;
delay = delay || 10;
var start = Number(new Date());
if ( typeof dom === "string" ) {
dom = document.getElementById( dom );
}
function step() {
var now = Number(new Date()),
elapsed = now - start,
pos = elapsed / interval,
value = ~~interpolate( 0, 500, pos ); // 0-500px (progress bar)
dom.style.width = value + "px";
if ( elapsed < interval )
setTimeout( step, delay );
}
setTimeout( step, delay );
}
Revisa este:
class Timer {
constructor(fun,delay) {
this.timer=setTimeout(fun, delay)
this.stamp=new Date()
}
get(){return ((this.timer._idleTimeout - (new Date-this.stamp))/1000) }
clear(){return (this.stamp=null, clearTimeout(this.timer))}
}
Hacer un temporizador:
let smtg = new Timer(()=>{do()}, 3000})
Sigue siendo:
smth.get()
Borrar tiempo de espera
smth.clear()
Si alguien mira hacia atrás en esto. He salido con un gestor de tiempo de espera e intervalo que puede obtener el tiempo restante en un tiempo de espera o intervalo, así como también hacer otras cosas. Lo agregaré para que sea más ingenioso y preciso, pero parece funcionar bastante bien (aunque tengo algunas ideas más para hacerlo aún más preciso):
Si no puede modificar el código de la biblioteca, deberá redefinir setTimeout para que se ajuste a sus propósitos. Aquí hay un ejemplo de lo que podrías hacer:
(function () {
var nativeSetTimeout = window.setTimeout;
window.bindTimeout = function (listener, interval) {
function setTimeout(code, delay) {
var elapsed = 0,
h;
h = window.setInterval(function () {
elapsed += interval;
if (elapsed < delay) {
listener(delay - elapsed);
} else {
window.clearInterval(h);
}
}, interval);
return nativeSetTimeout(code, delay);
}
window.setTimeout = setTimeout;
setTimeout._native = nativeSetTimeout;
};
}());
window.bindTimeout(function (t) {console.log(t + "ms remaining");}, 100);
window.setTimeout(function () {console.log("All done.");}, 1000);
Esto no es código de producción, pero debería ponerlo en el camino correcto. Tenga en cuenta que solo puede enlazar un oyente por timeout. No he hecho pruebas exhaustivas con esto, pero funciona en Firebug.
Una solución más robusta usaría la misma técnica de ajuste de setTimeout, pero en su lugar usaría un mapa del timeoutId devuelto a los oyentes para manejar múltiples oyentes por timeout. También podría considerar envolver clearTimeout para que pueda desconectar su oyente si se agota el tiempo de espera.
Solo para el registro, hay una manera de obtener el tiempo restante en node.js:
var timeout = setTimeout(function() {}, 3600 * 1000);
setInterval(function() {
console.log(''Time left: ''+getTimeLeft(timeout)+''s'');
}, 2000);
function getTimeLeft(timeout) {
return Math.ceil((timeout._idleStart + timeout._idleTimeout - Date.now()) / 1000);
}
Huellas dactilares:
$ node test.js
Time left: 3599s
Time left: 3597s
Time left: 3595s
Time left: 3593s
Esto no parece funcionar en Firefox, pero como node.js es javascript, pensé que esta observación podría ser útil para las personas que buscan la solución de nodo.
(function(){
window.activeCountdowns = [];
window.setCountdown = function (code, delay, callback, interval) {
var timeout = delay;
var timeoutId = setTimeout(function(){
clearCountdown(timeoutId);
return code();
}, delay);
window.activeCountdowns.push(timeoutId);
setTimeout(function countdown(){
var key = window.activeCountdowns.indexOf(timeoutId);
if (key < 0) return;
timeout -= interval;
setTimeout(countdown, interval);
return callback(timeout);
}, interval);
return timeoutId;
};
window.clearCountdown = function (timeoutId) {
clearTimeout(timeoutId);
var key = window.activeCountdowns.indexOf(timeoutId);
if (key < 0) return;
window.activeCountdowns.splice(key, 1);
};
})();
//example
var t = setCountdown(function () {
console.log(''done'');
}, 15000, function (i) {
console.log(i / 1000);
}, 1000);