使用setInterval與clearInterval踩的小坑總結

KyleLAN發表於2018-03-15

現場回顧

每次啟動彈幕的時候會用setInterval產生一個定時器,每隔2秒產生一條新彈幕,一直迴圈。 當需要切換頁面需要關閉頁面時,使用clearInterval清理掉定時器,並且把已經產生的彈幕清空,簡略程式碼如下:

let barrageTimer = null;
// 迴圈生成彈幕,每次呼叫生成一條彈幕
function barrageStart() {
  barrageTimer = setInterval(()=>{
    createBarrage();
  },2000);
} 

// 關閉彈幕,並清理已生成的彈幕
function barrageEnd() {
  clearInterval(barrageTimer);
  barrageList = [];  
}

// 小程式頁面每次載入時呼叫
onShow() {
  barrageStart();
}
// 小程式頁面隱藏或切換後臺時呼叫
onHide() {
  barrageEnd();
}

複製程式碼

當我寫完這段程式碼時,自信滿滿,覺得執行起來一定沒問題,結果呢...... 頁面裡的彈幕定時器還在歡快地跑著,絲毫沒有收到clearInterval的影響...... 可以說是很氣人了,但是還是要保持微笑...

問題總結

查詢MDN後,明確setInterval被執行後其實會返回一個定時器的id,每生成一個定時器都會返回其id,相當於每次進入頁面的時候,都產生了一個定時器,當頁面快速切換的時候,有可能clearInterval還沒有把本次頁面產生的定時器清除,barrageTimer又被新的定時器id給覆蓋了,造成總有定時器在跑的結果。 想要解決這個問題也很簡單,在產生新的定時器前,檢查下,只要有舊的定時器id,再停止一次,防止定時器id相互覆蓋即可。

function barrageStart() {
  if (barrageTimer) {
    clearInterval(barrageTimer);
  }
  barrageTimer = setInterval(()=>{
    createBarrage();
  },2000);
} 

function barrageEnd() {
  clearInterval(barrageTimer);
  barrageTimer = 0;
  barrageList = [];  
}
複製程式碼

當然這還不夠,最好是能用一個陣列將定時器id直接存進去,需要清理的時候統一清理

let barrageTimer = null;
let barrageTimerList = []
function barrageStart() {
  barrageTimer = setInterval(()=>{
    createBarrage();
  },2000);
  barrageTimerList.push(barrageTimer)
} 

function barrageEnd() {
  barrageTimerList.forEach((item,index)=>{
    clearInterval(item)
  })
  barrageTimerList = []
  barrageTimer = 0;
  barrageList = [];  
}
複製程式碼

相關文章