Pause and resume setInterval

前端 未结 3 1294
隐瞒了意图╮
隐瞒了意图╮ 2020-12-04 20:13
window.setInterval(function(){
  //do stuff
}, milisec);

Is there a way to stop this interval at will, and to resume it from where it lasted? Say,

相关标签:
3条回答
  • 2020-12-04 20:26

    You should only need setTimeout with a go and 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();
    }    
    
    0 讨论(0)
  • 2020-12-04 20:39

    To piggyback off Alireza's answer, here's an ES6 class that does the same thing with a bit more functionality, and doesn't start right away. You can set a maximum number of times the timer will fire off before automatically stopping, and pause and resume any number of times before the next time it's set to fire off.

    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;
      }
    }
    
    0 讨论(0)
  • 2020-12-04 20:40

    Try this:

    1- when you want to pause the timer, calculate the remaining milliseconds and store it somewhere then call clearInterval.

    2- When you want to resume the timer, just make a call to setTimeout passing the remaining time stored in the previous step as the argument.

    3- And in setTimeout's callback you should call setInterval again.

    UPDATE: This is what you want, a changed version of javascript: pause setTimeout(); thanks to @Felix Kling

        function IntervalTimer(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;
        }
    

    Usage:

        var timer = new IntervalTimer(function () {
            alert("Done!");
        }, 5000);
    
        window.setTimeout(function () {
            timer.pause();
            window.setTimeout(function () {
                timer.resume();
            }, 5000);
        }, 2000);
    
    0 讨论(0)
提交回复
热议问题