Estou escrevendo um Javascript que interage com o código da biblioteca que não possuo e não pode (razoavelmente) alterar. Ele cria tempos limite de Javascript usados para mostrar a próxima pergunta em uma série de perguntas com limite de tempo. Este não é um código real porque está ofuscado além de toda esperança. Aqui está o que a biblioteca está fazendo:
....
// 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 );
Quero colocar uma barra de progresso na tela que preenche questionTime * 1000
interrogando o cronômetro criado por setTimeout
. O único problema é que parece não haver maneira de fazer isso. Existe uma getTimeout
função que estou perdendo? A única informação sobre tempos limite de Javascript que posso encontrar está relacionada apenas à criação via setTimeout( function, time)
e exclusão via clearTimeout( id )
.
Estou procurando uma função que retorna o tempo restante antes que um tempo limite seja acionado ou o tempo decorrido após a chamada de um tempo limite. Meu código de barras de progresso é assim:
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: Como encontro o tempo restante antes de um setTimeout () javascript?
Aqui está a solução que estou usando agora. Passei pela seção da biblioteca responsável pelos testes e desembaralhei o código (terrível e contra minhas permissões).
// 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 );
e aqui está meu código:
// wrapper para setTimeout function mySetTimeout (func, timeout) { tempos limite [n = setTimeout (func, tempo limite)] = { start: new Date (). getTime (), fim: nova data (). getTime () + tempo limite t: tempo limite } return n; }
Isso funciona muito bem em qualquer navegador que não seja o IE 6. Até mesmo no iPhone original, onde eu esperava que as coisas ficassem assíncronas.
fonte
Apenas para registro, há uma maneira de obter o tempo restante em 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); }
Impressões:
Isso não parece funcionar no firefox, mas como node.js é javascript, achei que essa observação poderia ser útil para pessoas que procuram a solução de nó.
fonte
getTime()
foi removido,_idleStart
já é a horaEDIT: Na verdade, acho que fiz um ainda melhor: https://stackoverflow.com/a/36389263/2378102
Escrevi esta função e a uso muito:
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() }
Faça um cronômetro:
a = new timer(function() { // What ever }, 3000)
Então, se você quiser o tempo restante, basta fazer:
fonte
As pilhas de eventos do Javascript não funcionam como você pensa.
Quando um evento de tempo limite é criado, ele é adicionado à fila de eventos, mas outros eventos podem ter prioridade enquanto aquele evento está sendo disparado, atrasando o tempo de execução e postergando o tempo de execução.
Exemplo: você cria um tempo limite com um atraso de 10 segundos para alertar algo na tela. Ele será adicionado à pilha de eventos e executado depois que todos os eventos atuais forem disparados (causando algum atraso). Então, quando o tempo limite é processado, o navegador ainda continua a capturar outros eventos e adicioná-los à pilha, o que causa mais atrasos no processamento. Se o usuário clicar ou digitar muito ctrl +, seus eventos terão prioridade sobre a pilha atual. Seus 10 segundos podem se transformar em 15 segundos ou mais.
Dito isso, há muitas maneiras de fingir quanto tempo se passou. Uma maneira é executar um setInterval logo depois de adicionar setTimeout à pilha.
Exemplo: Execute um settimeout com um retardo de 10 segundos (armazene esse retardo em um global). Em seguida, execute um setInterval que é executado a cada segundo para subtrair 1 do atraso e gerar o atraso restante. Por causa de como a pilha de eventos pode influenciar o tempo real (descrito acima), isso ainda não será preciso, mas fornece uma contagem.
Resumindo, não há uma maneira real de obter o tempo restante. Existem apenas maneiras de tentar transmitir uma estimativa ao usuário.
fonte
Específico para Node.js do lado do servidor
Nenhuma das opções acima realmente funcionou para mim e, depois de inspecionar o objeto de tempo limite, parecia que tudo era relativo a quando o processo começou. O seguinte funcionou para mim:
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);
Resultado:
14 ... 3 2 1 Timer executed -0 -1 ... node -v v9.11.1
Saída editada por questões de brevidade, mas esta função básica fornece um tempo aproximado até a execução ou desde a execução. Como outros mencionaram, nada disso será exato devido à forma como o nó é processado, mas se eu quiser suprimir uma solicitação que foi executada há menos de 1 minuto e armazenei o cronômetro, não vejo por que isso não funcionam como uma verificação rápida. Pode ser interessante fazer malabarismos com objetos com o refreshtimer na versão 10.2+.
fonte
Você pode modificar
setTimeout
para armazenar o tempo de término de cada timeout em um mapa e criar uma função chamadagetTimeout
para obter o tempo restante para um timeout com um determinado id.Esta foi a solução do super , mas eu a modifiquei para usar um pouco menos de memória
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);
Aqui está uma versão
getTimeout
reduzida deste 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 isso seja tão útil para você quanto foi para mim! :)
fonte
Não, mas você pode ter seu próprio setTimeout / setInterval para animação em sua função.
Digamos que sua pergunta seja assim:
function myQuestion() { // animate the progress bar for 1 sec animate( "progressbar", 1000 ); // do the question stuff // ... }
E sua animação será controlada por estas 2 funções:
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 ); }
fonte
Se alguém está olhando para trás. Eu criei um gerenciador de tempo limite e intervalo que pode obter o tempo restante em um tempo limite ou intervalo, bem como fazer outras coisas. Vou acrescentá-lo para torná-lo mais bacana e preciso, mas parece funcionar muito bem como está (embora eu tenha mais algumas ideias para torná-lo ainda mais preciso):
https://github.com/vhmth/Tock
fonte
A pergunta já foi respondida, mas vou acrescentar minha parte. Apenas ocorreu para mim.
Use
setTimeout
darecursion
seguinte maneira: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"); }
Eu acho que o código é autoexplicativo
fonte
Verifique 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))} }
Faça um cronômetro:
let smtg = new Timer(()=>{do()}, 3000})
Obtenha permanecer:
Limpe o tempo limite
fonte
(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);
fonte
Parei aqui procurando essa resposta, mas estava pensando demais no meu problema. Se você está aqui porque precisa apenas de controlar o tempo enquanto define o tempo, esta é outra maneira de fazer isso:
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);
fonte
Uma maneira mais rápida e fácil:
tmo = 1000; start = performance.now(); setTimeout(function(){ foo(); },tmo);
Você pode obter o tempo restante com:
fonte