Estoy escribiendo algo de Javascript que interactúa con el código de la biblioteca que no soy de mi propiedad y que no puedo (razonablemente) cambiar. Crea tiempos de espera de Javascript que se utilizan 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 está haciendo la biblioteca:
....
// 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 questionTime * 1000
al interrogar el temporizador creado por setTimeout
. El único problema es que parece que no hay forma de hacer esto. ¿Hay una getTimeout
función que me falta? La única información sobre los tiempos de espera de Javascript que puedo encontrar está relacionada únicamente con la creación setTimeout( function, time)
y eliminación mediante clearTimeout( id )
.
Estoy buscando una función que devuelva el tiempo restante antes de que se active un 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 setTimeout () de javascript?
Aquí está la solución que estoy usando ahora. Revisé 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:
// contenedor para setTimeout function mySetTimeout (func, timeout) { tiempos de espera [n = setTimeout (func, timeout)] = { inicio: nueva fecha (). getTime (), fin: nueva fecha (). getTime () + tiempo de espera t: tiempo de espera } return n; }
Esto funciona bastante bien en cualquier navegador que no sea IE 6. Incluso en el iPhone original, donde esperaba que las cosas se volvieran asincrónicas.
fuente
Solo para que conste, 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 este comentario podría ser útil para las personas que buscan la solución de nodo.
fuente
getTime()
se elimina,_idleStart
ya es el momentoEDITAR: De hecho, creo que hice uno aún 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() }
Haz un temporizador:
a = new timer(function() { // What ever }, 3000)
Entonces, si quieres el tiempo restante, haz lo siguiente:
fuente
Las pilas de eventos de Javascript no funcionan como usted pensaría.
Cuando se crea un evento de tiempo de espera, se agrega a la cola de eventos, pero otros eventos pueden tener prioridad mientras se activa 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 en la pantalla. Se agregará a la pila de eventos y se ejecutará después de que se activen todos los eventos actuales (causando cierto retraso). Luego, cuando se procesa el tiempo de espera, el navegador aún 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 hace mucho ctrl + tipeo, sus eventos tienen prioridad sobre la pila actual. Tus 10 segundos pueden convertirse en 15 segundos o más.
Dicho esto, hay muchas formas de fingir cuánto tiempo ha pasado. Una forma es ejecutar setInterval justo después de agregar setTimeout a la pila.
Ejemplo: realizar un tiempo de espera establecido con un retraso de 10 segundos (almacenar ese retraso en un global) Luego, realice un setInterval que se ejecute cada segundo para restar 1 del retraso y generar el retraso restante. Debido a cómo la pila de eventos puede influir en el tiempo real (descrito anteriormente), esto aún no será exacto, pero da un recuento.
En resumen, no hay una forma real de obtener el tiempo restante. Solo hay formas de intentar transmitir un presupuesto al usuario.
fuente
Específico de Node.js del lado del servidor
Nada de lo anterior realmente funcionó para mí, y después de inspeccionar el objeto de tiempo de espera, parecía que todo era relativo a cuando comenzó el proceso. Lo siguiente funcionó para mí:
myTimer = setTimeout(function a(){console.log('Timer executed')},15000); function getTimeLeft(timeout){ console.log(Math.ceil((timeout._idleStart + timeout._idleTimeout)/1000 - process.uptime())); } setInterval(getTimeLeft,1000,myTimer);
Salida:
14 ... 3 2 1 Timer executed -0 -1 ... node -v v9.11.1
Salida editada por brevedad, pero esta función básica da un tiempo aproximado hasta la ejecución o desde la ejecución. Como mencionan otros, nada de esto será exacto debido a la forma en que procesa el nodo, pero si quiero suprimir una solicitud que se ejecutó hace menos de 1 minuto y guardé el temporizador, no veo por qué esto no lo haría. funciona como una comprobación rápida. Podría ser interesante hacer malabarismos con objetos con refreshtimer en 10.2+.
fuente
Puede modificar
setTimeout
para almacenar la hora de finalización de cada tiempo de espera en un mapa y crear una función llamadagetTimeout
para obtener el tiempo restante para un tiempo de espera con una determinada identificación.Esta fue la solución de Super , pero la modifiqué para usar un poco menos de memoria
let getTimeout = (() => { // IIFE let _setTimeout = setTimeout, // Reference to the original setTimeout map = {}; // Map of all timeouts with their end times setTimeout = (callback, delay) => { // Modify setTimeout let id = _setTimeout(callback, delay); // Run the original, and store the id map[id] = Date.now() + delay; // Store the end time return id; // Return the id }; return (id) => { // The actual getTimeout function // If there was no timeout with that id, return NaN, otherwise, return the time left clamped to 0 return map[id] ? Math.max(map[id] - Date.now(), 0) : NaN; } })();
Uso:
// go home in 4 seconds let redirectTimeout = setTimeout(() => { window.location.href = "/index.html"; }, 4000); // display the time left until the redirect setInterval(() => { document.querySelector("#countdown").innerHTML = `Time left until redirect ${getTimeout(redirectTimeout)}`; },1);
Aquí hay una versión reducida de este
getTimeout
IIFE :let getTimeout=(()=>{let t=setTimeout,e={};return setTimeout=((a,o)=>{let u=t(a,o);return e[u]=Date.now()+o,u}),t=>e[t]?Math.max(e[t]-Date.now(),0):NaN})();
¡Espero que esto sea tan útil para ti como lo fue para mí! :)
fuente
No, pero puede tener su propio setTimeout / setInterval para la animación en su función.
Digamos que su pregunta se ve 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 ); }
fuente
Si alguien está mirando hacia atrás en esto. He creado un administrador de tiempo muerto e intervalo que puede darte el tiempo restante en un tiempo muerto o intervalo, además de hacer algunas otras cosas. Lo agregaré para hacerlo más ingenioso y preciso, pero parece funcionar bastante bien tal como está (aunque tengo algunas ideas más para hacerlo aún más preciso):
https://github.com/vhmth/Tock
fuente
La pregunta ya ha sido respondida pero agregaré mi granito de arena. Simplemente se me ocurrió.
Úselo
setTimeout
de larecursion
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 se explica por sí mismo.
fuente
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))} }
Haz un temporizador:
let smtg = new Timer(()=>{do()}, 3000})
Obtener permanecer:
Limpiar el tiempo de espera
fuente
(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);
fuente
Pasé por aquí buscando esta respuesta, pero estaba pensando demasiado en mi problema. Si está aquí porque solo necesita realizar un seguimiento del tiempo mientras está configuradoTimeout está en progreso, aquí hay otra forma de hacerlo:
var focusTime = parseInt(msg.time) * 1000 setTimeout(function() { alert('Nice Job Heres 5 Schrute bucks') clearInterval(timerInterval) }, focusTime) var timerInterval = setInterval(function(){ focusTime -= 1000 initTimer(focusTime / 1000) }, 1000);
fuente
Una forma más rápida y sencilla:
tmo = 1000; start = performance.now(); setTimeout(function(){ foo(); },tmo);
Puede obtener el tiempo restante con:
fuente