javascript: 暂停 setTimeout();

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3969475/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 06:55:19  来源:igfitidea点击:

javascript: pause setTimeout();

javascripttimeout

提问by Hailwood

If I have an active timeout running that was set through var t = setTimeout("dosomething()", 5000),

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

Is there anyway to pause and resume it?

无论如何要暂停和恢复它?



有没有办法获得当前超时剩余的时间?


或者我必须在一个变量中,当设置超时时,存储当前时间,然后我们暂停,得到现在和那时之间的差异?

回答by Tim Down

You could wrap window.setTimeoutlike this, which I think is similar to what you were suggesting in the question:

你可以这样包装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();

回答by Sean Vieira

Something like this should do the trick.

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

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

回答by RoToRa

No. You'll need cancel it (clearTimeout), measure the time since you started it and restart it with the new time.

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

回答by yckart

A slightly modified version of Tim Downs answer. However, since Tim rolled backmy edit, I've to answer this myself. My solution makes it possible to use extra argumentsas third (3, 4, 5...) parameter and to clear the timer:

Tim Downs答案的稍微修改版本。但是,由于蒂姆回滚了我的编辑,我必须自己回答这个问题。我的解决方案可以使用 extraarguments作为第三个 (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();
}

As Tim mentioned, extra parameters are not available in IE lt 9, however I worked a bit around so that it will work in oldIE's too.

正如 Tim 提到的,额外的参数在 中不可用IE lt 9,但是我做了一些工作,以便它也可以在oldIE' 中使用。

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

用法: 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;

回答by T.J. Crowder

"Pause" and "resume" don't really make much sense in the context of setTimeout, which is a one-offthing. Do you mean setInterval? If so, no, you can't pause it, you can only cancel it (clearInterval) and then re-schedule it again. Details of all of these in the Timers sectionof the spec.

“暂停”和“继续”在 的上下文中没有多大意义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);

回答by TheCrzyMan

The Timeout was easy enough to find a solution for, but the Interval was a little bit trickier.

超时很容易找到解决方案,但间隔有点棘手。

I came up with the following two classes to solve this issues:

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

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

These can be implemented as such:

这些可以这样实现:

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

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

window.setTimeout("pt_hey.start()", 2000);

This example will set a pauseable Timeout (pt_hey) which is scheduled to alert, "hey" after two seconds. Another Timeout pauses pt_hey after one second. A third Timeout resumes pt_hey after two seconds. pt_hey runs for one second, pauses for one second, then resumes running. pt_hey triggers after three seconds.

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

Now for the trickier intervals

现在是更棘手的间隔

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

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

window.setTimeout("pi_hey.resume()", 6000);

This example sets a pauseable Interval (pi_hey) to write "hello world" in the console every two seconds. A timeout pauses pi_hey after five seconds. Another timeout resumes pi_hey after six seconds. So pi_hey will trigger twice, run for one second, pause for one second, run for one second, and then continue triggering every 2 seconds.

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

OTHER FUNCTIONS

其他功能

  • clearTimeout()and clearInterval()

    pt_hey.clearTimeout();and pi_hey.clearInterval();serve as an easy way to clear the timeouts and intervals.

  • getTimeLeft()

    pt_hey.getTimeLeft();and pi_hey.getTimeLeft();will return how many milliseconds till the next trigger is scheduled to occur.

  • clearTimeout()clearInterval()

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

  • 获取时间左()

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

回答by Ashraf Fayad

I needed to calculate the elapsed and remaining time to show a progress-bar. It was not easy using the accepted answer. 'setInterval' is better than 'setTimeout' for this task. So, I created this Timer class that you can use in any project.

我需要计算已用时间和剩余时间以显示进度条。使用公认的答案并不容易。对于此任务,“setInterval”比“setTimeout”更好。所以,我创建了这个 Timer 类,您可以在任何项目中使用它。

https://jsfiddle.net/ashraffayad/t0mmv853/

https://jsfiddle.net/ashraffayad/t0mmv853/

'use strict';


    //Constructor
    var Timer = function(cb, delay) {
      this.cb = cb;
      this.delay = delay;
      this.elapsed = 0;
      this.remaining = this.delay - self.elapsed;
    };

    console.log(Timer);

    Timer.prototype = function() {
      var _start = function(x, y) {
          var self = this;
          if (self.elapsed < self.delay) {
            clearInterval(self.interval);
            self.interval = setInterval(function() {
              self.elapsed += 50;
              self.remaining = self.delay - self.elapsed;
              console.log('elapsed: ' + self.elapsed, 
                          'remaining: ' + self.remaining, 
                          'delay: ' + self.delay);
              if (self.elapsed >= self.delay) {
                clearInterval(self.interval);
                self.cb();
              }
            }, 50);
          }
        },
        _pause = function() {
          var self = this;
          clearInterval(self.interval);
        },
        _restart = function() {
          var self = this;
          self.elapsed = 0;
          console.log(self);
          clearInterval(self.interval);
          self.start();
        };

      //public member definitions
      return {
        start: _start,
        pause: _pause,
        restart: _restart
      };
    }();


    // - - - - - - - - how to use this class

    var restartBtn = document.getElementById('restart');
    var pauseBtn = document.getElementById('pause');
    var startBtn = document.getElementById('start');

    var timer = new Timer(function() {
      console.log('Done!');
    }, 2000);

    restartBtn.addEventListener('click', function(e) {
      timer.restart();
    });
    pauseBtn.addEventListener('click', function(e) {
      timer.pause();
    });
    startBtn.addEventListener('click', function(e) {
      timer.start();
    });

回答by jeremiah.trein

/revive

/复活

ES6 Version using Class-y syntactic sugar

ES6 版本使用 Class-y 语法糖

(slightly-modified: added start())

(稍作修改:添加了 start())

class Timer {
  constructor(callback, delay) {
    this.callback = callback
    this.remainingTime = delay
    this.startTime
    this.timerId
  }

  pause() {
    clearTimeout(this.timerId)
    this.remainingTime -= new Date() - this.startTime
  }

  resume() {
    this.startTime = new Date()
    clearTimeout(this.timerId)
    this.timerId = setTimeout(this.callback, this.remainingTime)
  }

  start() {
    this.timerId = setTimeout(this.callback, this.remainingTime)
  }
}

// supporting code
const pauseButton = document.getElementById('timer-pause')
const resumeButton = document.getElementById('timer-resume')
const startButton = document.getElementById('timer-start')

const timer = new Timer(() => {
  console.log('called');
  document.getElementById('change-me').classList.add('wow')
}, 3000)

pauseButton.addEventListener('click', timer.pause.bind(timer))
resumeButton.addEventListener('click', timer.resume.bind(timer))
startButton.addEventListener('click', timer.start.bind(timer))
<!doctype html>
<html>
<head>
  <title>Traditional HTML Document. ZZz...</title>
  <style type="text/css">
    .wow { color: blue; font-family: Tahoma, sans-serif; font-size: 1em; }
  </style>
</head>
<body>
  <h1>DOM &amp; JavaScript</h1>

  <div id="change-me">I'm going to repaint my life, wait and see.</div>

  <button id="timer-start">Start!</button>
  <button id="timer-pause">Pause!</button>
  <button id="timer-resume">Resume!</button>
</body>
</html>

回答by Fabien Snauwaert

I needed to be able to pause setTimeout() for slideshow-like feature.

我需要能够暂停 setTimeout() 以实现类似幻灯片的功能。

Here is my own implementation of a pausable timer. It integrates comments seen on Tim Down's answer, such as better pause (kernel's comment) and a form of prototyping (Umur Gedik's comment.)

这是我自己实现的可暂停计时器。它集成了在 Tim Down 的回答中看到的评论,例如更好的暂停(内核的评论)和一种原型设计(Umur Gedik 的评论)。

function Timer( callback, delay ) {

    /** Get access to this object by value **/
    var self = this;



    /********************* PROPERTIES *********************/
    this.delay = delay;
    this.callback = callback;
    this.starttime;// = ;
    this.timerID = null;


    /********************* METHODS *********************/

    /**
     * Pause
     */
    this.pause = function() {
        /** If the timer has already been paused, return **/
        if ( self.timerID == null ) {
            console.log( 'Timer has been paused already.' );
            return;
        }

        /** Pause the timer **/
        window.clearTimeout( self.timerID );
        self.timerID = null;    // this is how we keep track of the timer having beem cleared

        /** Calculate the new delay for when we'll resume **/
        self.delay = self.starttime + self.delay - new Date().getTime();
        console.log( 'Paused the timer. Time left:', self.delay );
    }


    /**
     * Resume
     */
    this.resume = function() {
        self.starttime = new Date().getTime();
        self.timerID = window.setTimeout( self.callback, self.delay );
        console.log( 'Resuming the timer. Time left:', self.delay );
    }


    /********************* CONSTRUCTOR METHOD *********************/

    /**
     * Private constructor
     * Not a language construct.
     * Mind var to keep the function private and () to execute it right away.
     */
    var __construct = function() {
        self.starttime = new Date().getTime();
        self.timerID = window.setTimeout( self.callback, self.delay )
    }();    /* END __construct */

}   /* END Timer */

Example:

例子:

var timer = new Timer( function(){ console.log( 'hey! this is a timer!' ); }, 10000 );
timer.pause();

To test the code out, use timer.resume()and timer.pause()a few times and check how much time is left. (Make sure your console is open.)

要测试代码,请使用timer.resume()timer.pause()几次并检查还剩多少时间。(确保您的控制台已打开。)

Using this object in place of setTimeout() is as easy as replacing timerID = setTimeout( mycallback, 1000)with timer = new Timer( mycallback, 1000 ). Then timer.pause()and timer.resume()are available to you.

到位的setTimeout()的使用对象是一样容易更换timerID = setTimeout( mycallback, 1000)timer = new Timer( mycallback, 1000 )。然后timer.pause()timer.resume()可供您使用。

回答by John Hartsock

You could look into clearTimeout()

你可以看看clearTimeout()

or pause depending on a global variable that is set when a certain condition is hit. Like a button is pressed.

或暂停取决于满足特定条件时设置的全局变量。就像一个按钮被按下一样。

  <button onclick="myBool = true" > pauseTimeout </button>

  <script>
  var myBool = false;

  var t = setTimeout(function() {if (!mybool) {dosomething()}}, 5000);
  </script>