[英]find the time left in a setTimeout()?
我正在编写一些与我不拥有的库代码交互的 Javascript,并且不能(合理地)更改。 它创建 Javascript 超时,用于显示一系列限时问题中的下一个问题。 这不是真正的代码,因为它被混淆得令人望而却步。 这是图书馆正在做的事情:
....
// 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
创建的计时器来填充questionTime * 1000
。 唯一的问题是,似乎没有办法做到这一点。 是否有我缺少的getTimeout
函数? 我能找到的有关 Javascript 超时的唯一信息仅与通过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() 之前的剩余时间?
这是我现在使用的解决方案。 我浏览了负责测试的库部分,并解读了代码(很糟糕,而且违反了我的权限)。
// 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 );
这是我的代码:
// wrapper for setTimeout function mySetTimeout( func, timeout ) { timeouts[ n = setTimeout( func, timeout ) ] = { start: new Date().getTime(), end: new Date().getTime() + timeout t: timeout } return n; }
这在不是 IE 6 的任何浏览器中都非常有效。即使是最初的 iPhone,我希望事情会变得异步。
只是为了记录,有一种方法可以在 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,我认为这句话可能对寻找 node 解决方案的人有所帮助。
编辑:我实际上认为我做了一个更好的: 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()
如果您无法修改库代码,则需要重新定义 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);
这不是生产代码,但它应该让您走上正轨。 请注意,每次超时只能绑定一个侦听器。 我没有对此进行广泛的测试,但它在 Firebug 中有效。
更健壮的解决方案将使用包装 setTimeout 的相同技术,而是使用从返回的 timeoutId 到侦听器的映射来处理每个超时的多个侦听器。 您也可以考虑包装 clearTimeout 以便在超时被清除时分离您的侦听器。
服务器端 Node.js 特定
以上都不对我有用,在检查超时对象后,看起来一切都与进程开始时有关。 以下对我有用:
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);
输出:
14
...
3
2
1
Timer executed
-0
-1
...
node -v
v9.11.1
为简洁起见编辑了输出,但此基本函数给出了执行前或执行后的大致时间。 正如其他人提到的,由于节点处理的方式,这一切都不是准确的,但是如果我想抑制不到 1 分钟前运行的请求,并且我存储了计时器,我不明白为什么这不会作为快速检查工作。 在 10.2+ 中使用 refreshtimer 处理对象可能很有趣。
Javascript 的事件堆栈不会按照您的想法运行。
创建超时事件后,它会被添加到事件队列中,但在触发该事件时其他事件可能优先,延迟执行时间并推迟运行时间。
示例:您创建了一个延迟 10 秒的超时来向屏幕发出警报。 它将被添加到事件堆栈中,并将在所有当前事件被触发后执行(导致一些延迟)。 然后,当超时被处理时,浏览器仍然继续捕获其他事件将它们添加到堆栈中,这导致处理中的进一步延迟。 如果用户单击或执行大量 ctrl+typing,则他们的事件优先于当前堆栈。 您的 10 秒可以变成 15 秒或更长。
话虽如此,有很多方法可以伪造已经过去了多少时间。 一种方法是在将 setTimeout 添加到堆栈后立即执行 setInterval。
示例:执行具有 10 秒延迟的设置超时(将该延迟存储在全局中)。 然后执行每秒运行一次的 setInterval 以从延迟中减去 1 并输出剩余的延迟。 由于事件堆栈如何影响实际时间(如上所述),这仍然不准确,但确实提供了一个计数。
简而言之,没有真正的方法来获得剩余时间。 只有几种方法可以尝试向用户传达估算值。
这可能是一种更好的方法,而且,您不需要更改已编写的代码:
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}}();
您可以修改setTimeout
以将每个超时的结束时间存储在地图中,并创建一个名为getTimeout
的函数以获取具有特定 id 的超时剩余时间。
这是super的解决方案,但我对其进行了修改以使用更少的内存
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;
}
})();
用法:
// 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);
这是此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})();
我希望这对你和我一样有用! :)
如果有人回顾这一点。 我已经推出了一个超时和间隔管理器,它可以让你在超时或间隔中剩余的时间以及做一些其他的事情。 我将添加它以使其更漂亮和更准确,但它似乎工作得相当好(尽管我有更多想法可以使它更准确):
不,但您可以在您的函数中为动画设置自己的 setTimeout/setInterval。
说你的问题是这样的:
function myQuestion() {
// animate the progress bar for 1 sec
animate( "progressbar", 1000 );
// do the question stuff
// ...
}
你的动画将由这两个函数处理:
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 );
}
问题已经得到回答,但我会补充一点。 它只是发生在我身上。
在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);
我在这里停下来寻找这个答案,但过度思考了我的问题。 如果你在这里是因为你只需要在 setTimeout 正在进行时跟踪时间,这里有另一种方法:
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);
一种更快、更简单的方法:
tmo = 1000;
start = performance.now();
setTimeout(function(){
foo();
},tmo);
您可以通过以下方式获得剩余时间:
timeLeft = tmo - (performance.now() - start);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.