找到setTimeout()中剩下的时间?

Jus*_*ake 84 javascript timeout 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 );
Run Code Online (Sandbox Code Playgroud)

我想questionTime * 1000通过询问创建的计时器在屏幕上放置一个进度条setTimeout.唯一的问题是,似乎没有办法做到这一点.有没有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);
}
Run Code Online (Sandbox Code Playgroud)

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 );
Run Code Online (Sandbox Code Playgroud)

这是我的代码:

// 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,我也希望它能够异步.

Flu*_*ffy 53

只是为了记录,有一种方法可以节省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);
}
Run Code Online (Sandbox Code Playgroud)

打印:

$ node test.js 
Time left: 3599s
Time left: 3597s
Time left: 3595s
Time left: 3593s
Run Code Online (Sandbox Code Playgroud)

这似乎不适用于firefox,但由于node.js是javascript,我认为这句话可能对寻找节点解决方案的人有所帮助.

  • 不确定它是否是新版本的节点或什么,但为了使其工作,我必须删除"getTime()"部分.似乎_idleStart现在已经是一个整数 (4认同)
  • 我刚刚在节点0.10中尝试了它,`getTime()`被删除了,`_idleStart`已经是时候了 (3认同)
  • 在节点6.3上不起作用,因为超时结构是这些信息的泄漏。 (2认同)

sup*_*per 48

编辑:我实际上认为我做了一个更好的: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()
}
Run Code Online (Sandbox Code Playgroud)

做一个计时器:

a = new timer(function() {
    // What ever
}, 3000)
Run Code Online (Sandbox Code Playgroud)

所以如果你想剩下的时间就这样做:

a.getTimeLeft()
Run Code Online (Sandbox Code Playgroud)

  • 美好而优雅. (5认同)

law*_*sea 25

如果您无法修改库代码,则需要重新定义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);
Run Code Online (Sandbox Code Playgroud)

这不是生产代码,但它应该让您走上正轨.请注意,每个超时只能绑定一个侦听器.我没有对此进行过广泛的测试,但它适用于Firebug.

更强大的解决方案将使用相同的包装setTimeout技术,而是使用从返回的timeoutId到侦听器的映射来处理每个超时的多个侦听器.您还可以考虑包装clearTimeout,以便在清除超时时分离侦听器.

  • 由于执行时间,这可能会在一段时间内漂移几毫秒.更安全的方法是记录启动超时的时间(新的Date()),然后从当前时间中减去它(另一个新的Date()) (11认同)

Joh*_*tts 6

服务器端 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);
Run Code Online (Sandbox Code Playgroud)

输出:

14
...
3
2
1
Timer executed
-0
-1
...

node -v
v9.11.1
Run Code Online (Sandbox Code Playgroud)

为简洁起见编辑了输出,但此基本函数给出了执行前或执行后的大致时间。正如其他人提到的,由于节点处理的方式,这一切都不是准确的,但是如果我想抑制不到 1 分钟前运行的请求,并且我存储了计时器,我不明白为什么这不会作为快速检查工作。在 10.2+ 中使用 refreshtimer 处理对象可能很有趣。


Dan*_*ial 5

更快、更简单的方法:

tmo = 1000;
start = performance.now();
setTimeout(function(){
    foo();
},tmo);
Run Code Online (Sandbox Code Playgroud)

您可以通过以下方式获取剩余时间:

 timeLeft = tmo - (performance.now() - start);
Run Code Online (Sandbox Code Playgroud)