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它,使其更加漂亮和更准确,但它似乎工作得很好(虽然我有更多的想法,使其更加准确):
这可能是一个更好的方法,另外,你不需要改变已经写好的代码:
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);