为什么一直设置新的间隔时间间隔会越来越快

Why the interval will become faster and faster if I keep setting new interval

我正在用两个按钮做一个非常简单的计时器:stopset

代码如下:

   <h1>0</h1>
   <button onclick = 'set()'>Set</button>
   <button onclick = 'stop()'>Stop</button>

     var click = false;
        let interval
    function set(){
        interval = setInterval(function(){
    document.querySelector('h1').textContent = parseFloat(document.querySelector('h1').textContent)+1
        },1000)
    }
    function stop(){
        window.clearInterval(interval)
    }

我发现如果一直按set按钮设置新的间隔,h1加1的速度会越来越快(比1000ms快很多) .

我知道我可以把两个按钮合为一个按钮,或者让设置的按钮变成display: none或者用其他方法来防止这种情况。

但我只是想知道为什么会这样。

有人可以向我解释一下为什么会这样吗?

感谢任何回复?

那是因为你没有在你的 set 函数上清除之前的间隔(只是重新分配),所以如果你点击 set 三次,你就是 运行 三个间隔.

正确的代码应该是:

function set(){
  clearInterval(interval);

  interval = setInterval(function(){
    document.querySelector('h1').textContent = parseFloat(document.querySelector('h1').textContent)+1
  }, 1000)
}

另一种方式,对用户更友好?

const h1_element = document.querySelector('h1')
    , btSet      = document.querySelector('#bt-set')
    , btStop     = document.querySelector('#bt-stop')
    ;
var interval = 0
  , counter  = 0
  ;
btSet.onclick =()=>
  {
  btSet.disabled = true
  btStop.disabled = false
  interval = setInterval( ()=> { h1_element.textContent = ++counter }, 1000 )
  }
btStop.onclick =()=>
  {
  clearInterval(interval)
  btSet.disabled  = false
  btStop.disabled = true
  }
<h1>0</h1>
<button id="bt-set">Set</button>
<button id="bt-stop" disabled>Stop</button>

另一种方式?更多可靠,更多优雅

利用 OOP:保证 唯一 间隔是每个 实例

运行

class IntervalManager {
   constructor(fn, delay){ this.fn= fn; this.delay= delay;}
   start() {this.stop(); this.id= setInterval(this.fn, this.delay);}
   stop() {if (this.id) clearInterval(this.id);}
}
//--- use it now

const counter = new IntervalManager(function(){
  let ui = document.querySelector('h1')
  ui.textContent = parseFloat(ui.textContent)+1
},1000);
<h1>0</h1>
<button onclick = 'counter.start()'>Set</button>
<button onclick = 'counter.stop()'>Stop</button>

下面的其他示例显示了使用此管理器的好处:

class IntervalManager {
   constructor(fn, i){ this.fn= fn; this.i= i;}
   start() {this.stop(); this.id= setInterval(this.fn, this.i);}
   stop() {if (this.id) clearInterval(this.id);}
}
//--- use it now
//-- example 1
const timer = new IntervalManager(() => {
  document.querySelector('#timer h4').textContent = new Date()
}, 1000)

//-- example 2
counterIncrem= 0
const counter = new IntervalManager(() => {
  counterIncrem++;
  document.querySelector('#counter h4').textContent = counterIncrem
}, 1000)
<section id="timer">
  <h1>Timer</h1>
  <h4>_</h4>
  <button onclick = 'timer.start()'>Start</button>
  <button onclick = 'timer.stop()'>Stop</button>
</section>


<section id="counter">
  <h1>counter</h1>
  <h4>_</h4>
  <button onclick = 'counter.start()'>Start</button>
  <button onclick = 'counter.stop()'>Stop</button>
</section>