Javascript - 暂停setInterval()

chr*_*ong 47 javascript setinterval

如何使用Javascript暂停和恢复setInterval()函数?

例如,也许我有一个秒表来告诉你你在网页上看到的秒数.有一个"暂停"和"恢复"按钮.clearInterval()在这里不起作用的原因是因为如果用户在第40秒和第800毫秒点击"暂停"按钮,当他点击"恢复"按钮时,经过的秒数必须增加1 200毫秒.如果我在timer变量上使用clearInterval()函数(单击暂停按钮时),然后再次对timer变量使用setInterval()函数(单击恢复按钮时),经过的秒数将增加1仅在1000毫秒后,这会破坏秒表的准确性.

那我该怎么做?

Jon*_*ann 92

您可以使用标志来跟踪状态:

var output = $('h1');
var isPaused = false;
var time = 0;
var t = window.setInterval(function() {
  if(!isPaused) {
    time++;
    output.text("Seconds: " + time);
  }
}, 1000);

//with jquery
$('.pause').on('click', function(e) {
  e.preventDefault();
  isPaused = true;
});

$('.play').on('click', function(e) {
  e.preventDefault();
  isPaused = false;
});
Run Code Online (Sandbox Code Playgroud)
h1 {
    font-family: Helvetica, Verdana, sans-serif;
    font-size: 12px;
}
Run Code Online (Sandbox Code Playgroud)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h1>Seconds: 0</h1>
<button class="play">Play</button>
<button class="pause">Pause</button>
Run Code Online (Sandbox Code Playgroud)

这正是我要做的,我不确定你是否可以实际暂停setInterval.

注意:这个系统很简单,对于不需要高精度的应用程序非常有效,但它不会考虑时间间隔之间的时间:如果你在半秒后点击暂停,然后点击播放你的时间将休息半秒钟.

  • 你不能PAUSE setInterval函数,你可以停止它(clearInterval),或让它运行.我提供的解决方案是OP问题的解决方案,我没有声称它在每种可能的情况下都有效. (3认同)

Vit*_*iyG 11

您不应该在间隔函数中测量时间.而只是节省计时器启动时的时间,并在计时器停止/暂停时测量差异.仅使用setInterval更新显示的值.因此,无需暂停计时器,您将以这种方式获得最佳准确性.

  • 为什么有人不应该测量间隔时间?如果他们想显示实时计时器/倒计时,那么他们就需要每秒重新计算经过的持续时间,为什么不在那里跟踪它呢? (2认同)

ome*_*mer 10

我写了一个简单的 ES6 类,可能会派上用场。受到/sf/answers/4100664291/答案的启发

export class IntervalTimer {
    callbackStartTime;
    remaining = 0;
    paused = false;
    timerId = null;
    _callback;
    _delay;

    constructor(callback, delay) {
        this._callback = callback;
        this._delay = delay;
    }

    pause() {
        if (!this.paused) {
            this.clear();
            this.remaining = new Date().getTime() - this.callbackStartTime;
            this.paused = true;
        }
    }

    resume() {
        if (this.paused) {
            if (this.remaining) {
                setTimeout(() => {
                    this.run();
                    this.paused = false;
                    this.start();
                }, this.remaining);
            } else {
                this.paused = false;
                this.start();
            }
        }
    }

    clear() {
        clearInterval(this.timerId);
    }

    start() {
        this.clear();
        this.timerId = setInterval(() => {


            this.run();
        }, this._delay);
    }

    run() {
        this.callbackStartTime = new Date().getTime();
        this._callback();
    }
}
Run Code Online (Sandbox Code Playgroud)

用法非常简单,

const interval = new IntervalTimer(console.log('aaa'), 3000);
interval.start();
interval.pause();
interval.resume();
interval.clear();
Run Code Online (Sandbox Code Playgroud)


sbg*_*ran 7

虽然@Jonas Giuro在说:

你不能PAUSE setInterval函数,你可以停止它(clearInterval),或让它运行

另一方面,可以使用@VitaliyG建议的方法模拟这种行为:

您不应该在间隔函数中测量时间.而只是节省计时器启动时的时间,并在计时器停止/暂停时测量差异.仅使用setInterval更新显示的值.

var output = $('h1');
var isPaused = false;
var time = new Date();
var offset = 0;
var t = window.setInterval(function() {
  if(!isPaused) {
    var milisec = offset + (new Date()).getTime() - time.getTime();
    output.text(parseInt(milisec / 1000) + "s " + (milisec % 1000));
  }
}, 10);

//with jquery
$('.toggle').on('click', function(e) {
  e.preventDefault();
  isPaused = !isPaused;
  if (isPaused) {
    offset += (new Date()).getTime() - time.getTime();
  } else {
    time = new Date();
  }

});
Run Code Online (Sandbox Code Playgroud)
h1 {
    font-family: Helvetica, Verdana, sans-serif;
    font-size: 12px;
}
Run Code Online (Sandbox Code Playgroud)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h1>Seconds: 0</h1>
<button class="toggle">Toggle</button>
Run Code Online (Sandbox Code Playgroud)


Aar*_*ber 5

为什么不使用更简单的方法?添加课程!

只需添加一个告诉间隔什么都不做的类。例如:悬停。

var i = 0;
this.setInterval(function() {
  if(!$('#counter').hasClass('pauseInterval')) { //only run if it hasn't got this class 'pauseInterval'
    console.log('Counting...');
    $('#counter').html(i++); //just for explaining and showing
  } else {
    console.log('Stopped counting');
  }
}, 500);

/* In this example, I'm adding a class on mouseover and remove it again on mouseleave. You can of course do pretty much whatever you like */
$('#counter').hover(function() { //mouse enter
    $(this).addClass('pauseInterval');
  },function() { //mouse leave
    $(this).removeClass('pauseInterval');
  }
);

/* Other example */
$('#pauseInterval').click(function() {
  $('#counter').toggleClass('pauseInterval');
});
Run Code Online (Sandbox Code Playgroud)
body {
  background-color: #eee;
  font-family: Calibri, Arial, sans-serif;
}
#counter {
  width: 50%;
  background: #ddd;
  border: 2px solid #009afd;
  border-radius: 5px;
  padding: 5px;
  text-align: center;
  transition: .3s;
  margin: 0 auto;
}
#counter.pauseInterval {
  border-color: red;  
}
Run Code Online (Sandbox Code Playgroud)
<!-- you'll need jQuery for this. If you really want a vanilla version, ask -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>


<p id="counter">&nbsp;</p>
<button id="pauseInterval">Pause</button></p>
Run Code Online (Sandbox Code Playgroud)

我一直在寻找这种快速,简便的方法,因此,我发布了多个版本,以尽可能多地向人们介绍该方法。


Иль*_*ько 5

我的简单方法:

function Timer (callback, delay) {
  let callbackStartTime
  let remaining = 0

  this.timerId = null
  this.paused = false

  this.pause = () => {
    this.clear()
    remaining -= Date.now() - callbackStartTime
    this.paused = true
  }
  this.resume = () => {
    window.setTimeout(this.setTimeout.bind(this), remaining)
    this.paused = false
  }
  this.setTimeout = () => {
    this.clear()
    this.timerId = window.setInterval(() => {
      callbackStartTime = Date.now()
      callback()
    }, delay)
  }
  this.clear = () => {
    window.clearInterval(this.timerId)
  }

  this.setTimeout()
}

Run Code Online (Sandbox Code Playgroud)

如何使用:

let seconds = 0
const timer = new Timer(() => {
  seconds++
  
  console.log('seconds', seconds)

  if (seconds === 8) {
    timer.clear()

    alert('Game over!')
  }
}, 1000)

timer.pause()
console.log('isPaused: ', timer.paused)

setTimeout(() => {
  timer.resume()
  console.log('isPaused: ', timer.paused)
}, 2500)


function Timer (callback, delay) {
  let callbackStartTime
  let remaining = 0

  this.timerId = null
  this.paused = false

  this.pause = () => {
    this.clear()
    remaining -= Date.now() - callbackStartTime
    this.paused = true
  }
  this.resume = () => {
    window.setTimeout(this.setTimeout.bind(this), remaining)
    this.paused = false
  }
  this.setTimeout = () => {
    this.clear()
    this.timerId = window.setInterval(() => {
      callbackStartTime = Date.now()
      callback()
    }, delay)
  }
  this.clear = () => {
    window.clearInterval(this.timerId)
  }

  this.setTimeout()
}
Run Code Online (Sandbox Code Playgroud)

代码写得很快,没有重构,如果你想让我改进代码并给出ES2015版本(类),请提高我的答案的评级。