Пауза и возобновление setInterval

window.setInterval(function(){
  //do stuff
}, milisec);

Есть ли способ остановить этот интервал по своему желанию и возобновить его с того места, где он длился? Скажем, код запускается каждые 5 секунд. Я останавливаю его в середине второй секунды, когда возобновляется, я хочу, чтобы он запустил оставшиеся 3 секунды и продолжал работать через каждые 5 сек. еще раз.

Ответ 1

Попробуйте следующее:

1-, когда вы хотите pause таймер, вычислить оставшиеся миллисекунды и сохранить его где-нибудь, затем вызвать clearInterval.

2- Когда вы хотите resume таймер, просто сделайте вызов setTimeout, передав оставшееся время, сохраненное на предыдущем шаге, в качестве аргумента.

3- И в обратном вызове setTimeout вы должны снова позвонить setInterval.

UPDATE: это то, что вы хотите, измененная версия javascript: pause setTimeout(); благодаря @Felix Kling

    function InvervalTimer(callback, interval) {
        var timerId, startTime, remaining = 0;
        var state = 0; //  0 = idle, 1 = running, 2 = paused, 3= resumed

        this.pause = function () {
            if (state != 1) return;

            remaining = interval - (new Date() - startTime);
            window.clearInterval(timerId);
            state = 2;
        };

        this.resume = function () {
            if (state != 2) return;

            state = 3;
            window.setTimeout(this.timeoutCallback, remaining);
        };

        this.timeoutCallback = function () {
            if (state != 3) return;

            callback();

            startTime = new Date();
            timerId = window.setInterval(callback, interval);
            state = 1;
        };

        startTime = new Date();
        timerId = window.setInterval(callback, interval);
        state = 1;
    }

Использование:

    var timer = new InvervalTimer(function () {
        alert("Done!");
    }, 5000);

    window.setTimeout(function () { timer.pause(); window.setTimeout(function () {  timer.resume(); }, 5000); }, 2000);

Ответ 2

Вам нужно только setTimeout с go и stop - http://jsfiddle.net/devitate/QjdUR/1/

var cnt = 0;
var fivecnt = 0;
var go = false;

function timer() {
    if(!go)
        return;
    cnt++;
    if(cnt >= 5){
        cnt=0;
        everyFive();
    }
    jQuery("#counter").text(cnt);
    setTimeout(timer, 1000);
}

function everyFive(){
    fivecnt++;
    jQuery("#fiver").text(fivecnt);
}

function stopTimer(){
    go = false;  
} 
function startTimer(){
    go = true;
    timer();
}    

Ответ 3

Чтобы ответить на вопрос Alireza, вот класс ES6, который делает то же самое с немного большей функциональностью и не запускается сразу. Вы можете установить максимальное количество раз, когда таймер погаснет, прежде чем автоматически останавливаться, и приостанавливать и возобновлять любое количество раз до того, как в следующий раз он отключится.

export default class IntervalTimer{
  constructor(name, callback, interval, maxFires = null){
    this.remaining = 0;
    this.state = 0; //  0 = idle, 1 = running, 2 = paused, 3= resumed

    this.name = name;
    this.interval = interval; //in ms
    this.callback = callback;
    this.maxFires = maxFires;
    this.pausedTime = 0; //how long we've been paused for

    this.fires = 0;
  }

  proxyCallback(){
    if(this.maxFires != null && this.fires >= this.maxFires){
      this.stop();
      return;
    }
    this.lastTimeFired = new Date();
    this.fires++;
    this.callback();
  }

  start(){
    this.log.info('Starting Timer ' + this.name);
    this.timerId = setInterval(() => this.proxyCallback(), this.interval);
    this.lastTimeFired = new Date();
    this.state = 1;
    this.fires = 0;
  }

  pause(){
    if (this.state != 1 && this.state != 3) return;

    this.log.info('Pausing Timer ' + this.name);

    this.remaining = this.interval - (new Date() - this.lastTimeFired) + this.pausedTime;
    this.lastPauseTime = new Date();
    clearInterval(this.timerId);
    clearTimeout(this.resumeId);
    this.state = 2;
  }

  resume(){
    if (this.state != 2) return;

    this.pausedTime += new Date() - this.lastPauseTime;
    this.log.info(`Resuming Timer ${this.name} with ${this.remaining} remaining`);
    this.state = 3;
    this.resumeId = setTimeout(() => this.timeoutCallback(), this.remaining);
  }

  timeoutCallback(){
    if (this.state != 3) return;

    this.pausedTime = 0;
    this.proxyCallback();
    this.start();
  }

  stop(){
    if(this.state === 0) return;

    this.log.info('Stopping Timer %s. Fired %s/%s times', this.name, this.fires, this.maxFires);
    clearInterval(this.timerId);
    clearTimeout(this.resumeId);
    this.state = 0;
  }

  //set a new interval to use on the next interval loop
  setInterval(newInterval){
    this.log.info('Changing interval from %s to %s for %s', this.interval, newInterval, this.name);

    //if we're running do a little switch-er-oo
    if(this.state == 1){
      this.pause();
      this.interval = newInterval;
      this.resume();
    }
    //if we're already stopped, idle, or paused just switch it
    else{
      this.interval = newInterval;
    }
  }

  setMaxFires(newMax){
    if(newMax != null && this.fires >= newMax){
      this.stop();
    }
    this.maxFires = newMax;
  }
}