J'écris du Javascript qui interagit avec le code de bibliothèque que je ne possède pas et que je ne peux pas (raisonnablement) changer. Il crée des délais d'expiration Javascript utilisés pour afficher la question suivante dans une série de questions limitées dans le temps. Ce n'est pas du vrai code car il est obscurci au-delà de tout espoir. Voici ce que fait la bibliothèque:
....
// 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 );
Je veux mettre une barre de progression à l'écran qui se remplit questionTime * 1000
en interrogeant la minuterie créée par setTimeout
. Le seul problème est qu'il ne semble y avoir aucun moyen de le faire. Y a-t-il une getTimeout
fonction qui me manque? Les seules informations sur les délais d'expiration Javascript que je peux trouver concernent uniquement la création via setTimeout( function, time)
et la suppression via clearTimeout( id )
.
Je recherche une fonction qui renvoie soit le temps restant avant le déclenchement d'un timeout, soit le temps écoulé après l'appel d'un timeout. Mon code à barres de progression ressemble à ceci:
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: Comment trouver le temps restant avant un javascript setTimeout ()?
Voici la solution que j'utilise actuellement. J'ai parcouru la section bibliothèque chargée des tests, et j'ai déchiffré le code (terrible et contre mes autorisations).
// 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 );
et voici mon code:
// wrapper pour setTimeout function mySetTimeout (func, timeout) { timeouts [n = setTimeout (func, timeout)] = { début: nouvelle Date (). getTime (), end: new Date (). getTime () + timeout t: délai d'expiration } return n; }
Cela fonctionne assez parfaitement dans n'importe quel navigateur qui n'est pas IE 6. Même l'iPhone d'origine, où je m'attendais à ce que les choses deviennent asynchrones.
la source
Pour mémoire, il existe un moyen d'obtenir le temps restant dans 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); }
Impressions:
$ node test.js Time left: 3599s Time left: 3597s Time left: 3595s Time left: 3593s
Cela ne semble pas fonctionner dans Firefox, mais comme node.js est javascript, j'ai pensé que cette remarque pourrait être utile pour les personnes à la recherche de la solution de nœud.
la source
getTime()
est supprimé,_idleStart
c'est déjà l'heureEDIT: Je pense en fait que j'ai fait un encore meilleur: https://stackoverflow.com/a/36389263/2378102
J'ai écrit cette fonction et je l'utilise beaucoup:
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() }
Faire une minuterie:
a = new timer(function() { // What ever }, 3000)
Donc, si vous voulez le temps restant, faites simplement:
la source
Les piles d'événements de Javascript ne fonctionnent pas comme vous le pensez.
Lorsqu'un événement de délai d'expiration est créé, il est ajouté à la file d'attente d'événements, mais d'autres événements peuvent avoir la priorité pendant le déclenchement de cet événement, retardent le temps d'exécution et reportent le temps d'exécution.
Exemple: vous créez une temporisation avec un délai de 10 secondes pour alerter quelque chose à l'écran. Il sera ajouté à la pile d'événements et sera exécuté après le déclenchement de tous les événements actuels (entraînant un certain retard). Ensuite, lorsque le délai d'expiration est traité, le navigateur continue de capturer d'autres événements et les ajoute à la pile, ce qui entraîne des retards supplémentaires dans le traitement. Si l'utilisateur clique ou fait beaucoup de ctrl + tapant, ses événements ont priorité sur la pile actuelle. Vos 10 secondes peuvent devenir 15 secondes ou plus.
Cela étant dit, il existe de nombreuses façons de simuler le temps écoulé. Une façon consiste à exécuter un setInterval juste après avoir ajouté le setTimeout à la pile.
Exemple: effectuer un règlement avec un délai de 10 secondes (stocker ce délai dans un global). Ensuite, effectuez un setInterval qui s'exécute toutes les secondes pour soustraire 1 du délai et afficher le délai restant. En raison de la façon dont la pile d'événements peut influencer le temps réel (décrit ci-dessus), cela ne sera toujours pas précis, mais donne un décompte.
En bref, il n'y a pas vraiment de moyen d'obtenir le temps restant. Il n'y a que des moyens d'essayer de transmettre une estimation à l'utilisateur.
la source
Spécifique à Node.js côté serveur
Rien de ce qui précède n'a vraiment fonctionné pour moi, et après avoir inspecté l'objet timeout, il semblait que tout était relatif au démarrage du processus. Ce qui suit a fonctionné pour moi:
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);
Production:
14 ... 3 2 1 Timer executed -0 -1 ... node -v v9.11.1
Sortie éditée par souci de concision, mais cette fonction de base donne un temps approximatif jusqu'à l'exécution ou depuis l'exécution. Comme d'autres le mentionnent, rien de tout cela ne sera exact en raison de la façon dont le nœud traite, mais si je veux supprimer une requête qui a été exécutée il y a moins d'une minute et que j'ai stocké le minuteur, je ne vois pas pourquoi cela ne le ferait pas fonctionne comme un contrôle rapide. Cela pourrait être intéressant de jongler avec des objets avec refreshtimer dans 10.2+.
la source
Vous pouvez modifier
setTimeout
pour stocker l'heure de fin de chaque timeout dans une carte et créer une fonction appeléegetTimeout
pour obtenir le temps restant pour un timeout avec un certain identifiant.C'était la solution super , mais je l'ai modifiée pour utiliser un peu moins de mémoire
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; } })();
Usage:
// 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);
Voici une version
getTimeout
réduite de cet 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})();
J'espère que cela vous sera aussi utile qu'à moi! :)
la source
Non, mais vous pouvez avoir votre propre setTimeout / setInterval pour l'animation dans votre fonction.
Dites que votre question ressemble à ceci:
function myQuestion() { // animate the progress bar for 1 sec animate( "progressbar", 1000 ); // do the question stuff // ... }
Et votre animation sera gérée par ces 2 fonctions:
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 ); }
la source
Si quelqu'un regarde en arrière. Je suis sorti avec un gestionnaire de timeout et d'intervalle qui peut vous donner le temps restant dans un timeout ou un intervalle ainsi que faire d'autres choses. Je vais y ajouter pour le rendre plus astucieux et plus précis, mais il semble fonctionner assez bien tel quel (même si j'ai quelques idées supplémentaires pour le rendre encore plus précis):
https://github.com/vhmth/Tock
la source
La question a déjà reçu une réponse, mais j'ajouterai ma part. Cela m'est juste arrivé.
Utiliser
setTimeout
dans larecursion
manière suivante: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"); }
Je suppose que le code est explicite
la source
Vérifier celui-ci:
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))} }
Faire une minuterie:
let smtg = new Timer(()=>{do()}, 3000})
Restez:
Effacer le délai
la source
(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);
la source
Je me suis arrêté ici à la recherche de cette réponse, mais je réfléchissais trop à mon problème. Si vous êtes ici parce que vous avez juste besoin de garder une trace du temps pendant que vous êtes setTimeout est en cours, voici une autre façon de le faire:
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);
la source
Un moyen plus rapide et plus simple:
tmo = 1000; start = performance.now(); setTimeout(function(){ foo(); },tmo);
Vous pouvez obtenir le temps restant avec:
la source