findsetTimeout()中剩下的时间?

我正在写一些JavaScript与我不拥有的库代码交互,并且不能(合理地)改变。 它创buildJavascript超时,用于在一系列有时间限制的问题中显示下一个问题。 这不是真正的代码,因为它被混淆超出所有希望。 这是图书馆正在做的事情:

.... // 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 ); 

我想通过询问由setTimeout创build的计时器在屏幕上放置一个进度条来填充questionTime * 1000 。 唯一的问题是,似乎没有办法做到这一点。 有没有我失踪的getTimeout函数? 关于Javascript超时的唯一信息,我可以find仅与通过setTimeout( function, time)和通过clearTimeout( id )删除有关。

我正在寻找一个函数,该函数返回超时触发之前的剩余时间,或者调用超时之后的时间。 我的进度条代码如下所示:

 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: 如何在javascript setTimeout()之前find剩余的时间?


这是我现在使用的解决scheme。 我经历了负责testing的库部分,并解码了代码(可怕的,违反我的权限)。

 // 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 ); 

这是我的代码:

  //包装setTimeout
函数mySetTimeout(func,timeout){
    超时[n = setTimeout(func,timeout)] = {
        开始:新date()。getTime(),
        结束:新的date()。getTime()+超时
         t:超时
     }
    返回n;
 } 

这在任何不是IE 6的浏览器中都是非常适用的。即使是原来的iPhone,我也希望事物能够asynchronous。

如果你不能修改库代码,你需要重新定义setTimeout以适应你的目的。 下面是你可以做的一个例子:

 (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); 

这不是生产代码,但它应该把你放在正确的轨道上。 请注意,每个超时只能绑定一个侦听器。 我没有做过广泛的testing,但它在Firebug中有效。

一个更强大的解决scheme将使用相同的方法来包装setTimeout,而是使用返回的timeoutId中的映射到侦听器来处理每个超时的多个侦听器。 您也可以考虑包装clearTimeout,以便在清除超时时可以分离侦听器。

只是为了logging,有一种方法可以在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); } 

打印:

 $ node test.js Time left: 3599s Time left: 3597s Time left: 3595s Time left: 3593s 

这似乎并没有在Firefox通过,但由于node.js是JavaScript,我认为这个评论可能会有助于寻找节点解决scheme的人。

编辑:我其实觉得我做了一个更好的: https : //stackoverflow.com/a/36389263/2378102

我写了这个函数,我用了很多:

 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() } 

做一个计时器:

 a = new timer(function() { // What ever }, 3000) 

所以如果你想剩下的时间只是做:

 a.getTimeLeft() 

JavaScript的事件堆栈不会如何操作。

当一个超时事件被创build时,它会被添加到事件队列中,但是当这个事件被触发时,其他事件可能会被优先考虑,延迟执行时间并推迟运行时间。

例如:您创build一个延迟10秒的超时时间来提醒屏幕。 它将被添加到事件堆栈中,并在所有当前事件被触发后执行(导致一些延迟)。 然后,当处理超时时,浏览器仍然继续捕获其他事件将它们添加到堆栈,这导致进一步的处理延迟。 如果用户点击,或做了很多Ctrl +打字,他们的事件优先于当前的堆栈。 你的10秒钟可以变成15秒或更长时间。


这就是说,有很多方法可以假冒多less时间过去了。 一种方法是在将setTimeout添加到堆栈之后立即执行setInterval。

示例:以10秒的延迟执行settimeout(将该延迟存储在全局中)。 然后执行一个每秒运行的setInterval从延迟中减去1,并输出剩余的延迟。 由于事件堆栈如何影响实际时间(如上所述),这仍然是不准确的,但确实给出了一个计数。


总之,没有真正的方法来获得剩余的时间。 只有方法可以尝试并向用户传达估算值。

不,但是你可以在你的函数中拥有自己的setTimeout / setIntervalanimation。

说你的问题是这样的:

 function myQuestion() { // animate the progress bar for 1 sec animate( "progressbar", 1000 ); // do the question stuff // ... } 

而你的animation将由这两个function来处理:

 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 ); } 

如果有人回头看这个。 我已经出来了一个超时和间隔pipe理器,可以让你留在超时或间隔的时间,以及做一些其他的东西。 我会join它,使其更加漂亮和更准确,但它似乎工作得很好(虽然我有更多的想法,使其更加准确):

https://github.com/vhmth/Tock

这可能是一个更好的方法,另外,你不需要改变已经写好的代码:

 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; } })(); 

…而且被模仿:

 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}}(); 

问题已经回答了,但我会补充一点。 它只是发生在我身上。

recursion使用setTimeout如下:

 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"); } 

我猜代码是自我解释的

检查这一个:

 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))} } 

做一个计时器:

 let smtg = new Timer(()=>{do()}, 3000}) 

留下来:

 smth.get() 

清除超时

 smth.clear() 
  (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);