javascript:pause setTimeout();

Hai*_*ood 113 javascript timeout

如果我有一个已设置的活动超时运行var t = setTimeout("dosomething()", 5000),

反正有暂停和恢复吗?


有没有办法让剩余时间在当前超时?
或者我必须在变量中,当设置超时时,存储当前时间,然后我们暂停,从而获得现在和之间的差异?

Tim*_*own 243

你可以window.setTimeout像这样包装,我认为这与你在问题中建议的类似:

var Timer = function(callback, delay) {
    var timerId, start, remaining = delay;

    this.pause = function() {
        window.clearTimeout(timerId);
        remaining -= Date.now() - start;
    };

    this.resume = function() {
        start = Date.now();
        window.clearTimeout(timerId);
        timerId = window.setTimeout(callback, remaining);
    };

    this.resume();
};

var timer = new Timer(function() {
    alert("Done!");
}, 1000);

timer.pause();
// Do some stuff...
timer.resume();
Run Code Online (Sandbox Code Playgroud)

  • 如果你做`timer.resume(); timer.resume();`你最终会有两个并行超时.这就是为什么你要先`clearTimeout(timerId)`或者`if(timerId)返回;`恢复开始时的短路. (4认同)
  • @yckart:回头,抱歉.这是一个很好的补充,除了在`setTimeout()`中添加额外的参数在Internet Explorer <= 9中不起作用. (3认同)
  • 嘿,我喜欢这个答案,但我不得不拉:`var timerId,start,remaining;`在Class范围之外并添加`remaining = delay;`回到内部来捕获参数.像一个魅力的作品! (2认同)
  • 出于某种原因,这在初始化后只对我运行一次。 (2认同)

Sea*_*ira 17

这样的事情应该可以解决问题.

function Timer(fn, countdown) {
    var ident, complete = false;

    function _time_diff(date1, date2) {
        return date2 ? date2 - date1 : new Date().getTime() - date1;
    }

    function cancel() {
        clearTimeout(ident);
    }

    function pause() {
        clearTimeout(ident);
        total_time_run = _time_diff(start_time);
        complete = total_time_run >= countdown;
    }

    function resume() {
        ident = complete ? -1 : setTimeout(fn, countdown - total_time_run);
    }

    var start_time = new Date().getTime();
    ident = setTimeout(fn, countdown);

    return { cancel: cancel, pause: pause, resume: resume };
}
Run Code Online (Sandbox Code Playgroud)

  • 我将 `+new Date()` 更改为 `new Date().getTime()` 因为它更快:http://jsperf.com/date-vs-gettime (2认同)

RoT*_*oRa 9

不需要.您需要取消它(clearTimeout),测量自启动以来的时间并使用新时间重新启动它.


yck*_*art 7

Tim Downs的一个略微修改的版本回答.但是,由于蒂姆回滚了我的编辑,我自己回答这个问题.我的解决方案可以使用额外的arguments第三个(3,4,5 ...)参数并清除计时器:

function Timer(callback, delay) {
    var args = arguments,
        self = this,
        timer, start;

    this.clear = function () {
        clearTimeout(timer);
    };

    this.pause = function () {
        this.clear();
        delay -= new Date() - start;
    };

    this.resume = function () {
        start = new Date();
        timer = setTimeout(function () {
            callback.apply(self, Array.prototype.slice.call(args, 2, args.length));
        }, delay);
    };

    this.resume();
}
Run Code Online (Sandbox Code Playgroud)

正如蒂姆所提到的那样,额外的参数不可用IE lt 9,但是我有点工作,所以它也可以工作oldIE.

用法: new Timer(Function, Number, arg1, arg2, arg3...)

function callback(foo, bar) {
    console.log(foo); // "foo"
    console.log(bar); // "bar"
}

var timer = new Timer(callback, 1000, "foo", "bar");

timer.pause();
document.onclick = timer.resume;
Run Code Online (Sandbox Code Playgroud)


T.J*_*der 6

"暂停"和"简历"在上下文中并没有多大意义setTimeout,这是一次性的事情.你的意思是setInterval?如果是,不,你不能暂停它,你只能取消它(clearInterval)然后再重新安排它.规范的定时器部分中的所有这些的详细信息.

// Setting
var t = setInterval(doSomething, 1000);

// Pausing (which is really stopping)
clearInterval(t);
t = 0;

// Resuming (which is really just setting again)
t = setInterval(doSomething, 1000);
Run Code Online (Sandbox Code Playgroud)

  • 在setTimeout的上下文中,暂停和恢复仍然有意义. (14认同)

The*_*Man 6

Timeout很容易找到解决方案,但Interval有点棘手.

我想出了以下两个类来解决这个问题:

function PauseableTimeout(func, delay){
    this.func = func;

    var _now = new Date().getTime();
    this.triggerTime = _now + delay;

    this.t = window.setTimeout(this.func,delay);

    this.paused_timeLeft = 0;

    this.getTimeLeft = function(){
        var now = new Date();

        return this.triggerTime - now;
    }

    this.pause = function(){
        this.paused_timeLeft = this.getTimeLeft();

        window.clearTimeout(this.t);
        this.t = null;
    }

    this.resume = function(){
        if (this.t == null){
            this.t = window.setTimeout(this.func, this.paused_timeLeft);
        }
    }

    this.clearTimeout = function(){ window.clearTimeout(this.t);}
}

function PauseableInterval(func, delay){
    this.func = func;
    this.delay = delay;

    this.triggerSetAt = new Date().getTime();
    this.triggerTime = this.triggerSetAt + this.delay;

    this.i = window.setInterval(this.func, this.delay);

    this.t_restart = null;

    this.paused_timeLeft = 0;

    this.getTimeLeft = function(){
        var now = new Date();
        return this.delay - ((now - this.triggerSetAt) % this.delay);
    }

    this.pause = function(){
        this.paused_timeLeft = this.getTimeLeft();
        window.clearInterval(this.i);
        this.i = null;
    }

    this.restart = function(sender){
        sender.i = window.setInterval(sender.func, sender.delay);
    }

    this.resume = function(){
        if (this.i == null){
            this.i = window.setTimeout(this.restart, this.paused_timeLeft, this);
        }
    }

    this.clearInterval = function(){ window.clearInterval(this.i);}
}
Run Code Online (Sandbox Code Playgroud)

这些可以这样实现:

var pt_hey = new PauseableTimeout(function(){
    alert("hello");
}, 2000);

window.setTimeout(function(){
    pt_hey.pause();
}, 1000);

window.setTimeout("pt_hey.start()", 2000);
Run Code Online (Sandbox Code Playgroud)

此示例将设置一个可暂停的超时(pt_hey),计划在两秒钟后发出警报,"嘿".另一个超时在一秒后暂停pt_hey.第二次超时在两秒后恢复pt_hey.pt_hey运行一秒钟,暂停一秒钟,然后恢复运行.pt_hey在三秒后触发.

现在是更棘手的间隔

var pi_hey = new PauseableInterval(function(){
    console.log("hello world");
}, 2000);

window.setTimeout("pi_hey.pause()", 5000);

window.setTimeout("pi_hey.resume()", 6000);
Run Code Online (Sandbox Code Playgroud)

此示例设置一个可暂停的Interval(pi_hey),每两秒在控制台中写入"hello world".超时会在五秒后暂停pi_hey.六秒后,另一个超时恢复pi_hey.所以pi_hey将触发两次,运行一秒,暂停一秒,运行一秒,然后每2秒继续触发一次.

其他功能

  • clearTimeout()clearInterval()

    pt_hey.clearTimeout();pi_hey.clearInterval();作为清除超时和间隔的简单方法.

  • getTimeLeft()

    pt_hey.getTimeLeft();并且pi_hey.getTimeLeft();将返回多少毫秒,直到下一个触发预定要发生.

  • 我这样做是为了让你可以暂停间隔,而不是在触发时跳过一个电话.如果,在游戏中,每60秒释放一次加电,并且在它即将触发之前暂停游戏,使用您的方法,我将不得不等待另一分钟再次加电.这不是真正的暂停,只是忽略了一个电话.相反,我的方法实际上是暂停,因此,关于游戏玩法,"准时"被释放. (2认同)