這是全網唯一敢說真話的定時器解析,看完直接扔掉 setInterval,從此告別卡頓、延遲、內存泄漏!
作為前端工程師,定時任務誰沒寫過?但如果你還在用 setInterval
,甚至用第三方庫管理定時器——恭喜你,成功為項目埋下了一顆定時炸彈??。
我見過太多工作 3 年以上的程序員,還在用 setInterval(fn, 100)
做輪詢請求,結果頁面越用越卡,最后直接白屏。不是瀏覽器不行,是你寫法太騷啊!
今天我要用 3 個顛覆認知的騷操作,讓你徹底掌握定時器的正確打開方式。文末附手寫 防崩潰版 setInterval 源碼,直接抄作業!
一、血淚教訓:setInterval 的三大致命傷
1. 誤差累積陷阱
你以為下面代碼每秒精準執行?
setInterval(() => {
console.log('Hi!');
}, 1000);
錯! 當回調函數執行時間超過間隔時,下次執行會立即觸發,導致誤差累積:

(執行時間超過間隔時引發的連環車禍)
2. 內存泄漏鬼才
以下代碼有什么問題?
let data = fetchBigData();
setInterval(() => {
processData(data);
}, 1000);
data 永遠無法被垃圾回收! 因為閉包持有 data
引用,即使組件卸載,定時器仍在后臺運行。
3. 主線程卡頓
當頁面有復雜計算時,setInterval
的回調會排隊等待,出現跳幀現象:

(主線程阻塞導致定時器回調延遲執行)
二、究極解決方案:用 setTimeout 手搓高性能定時器
?? 對比實驗:遞歸 vs 普通 setTimeout
普通版(錯誤示范?):
function task() {
console.log('執行');
setTimeout(task, 1000);
}
task();
防崩版(正確姿勢?):
function customInterval(callback, delay) {
let start = Date.now()
let count = 0
function loop() {
const current = Date.now()
const elapsed = current - start
const targetNextTime = ++count * delay
// 計算下次執行的時間偏差
const deviation = targetNextTime - elapsed
const nextDelay = Math.max(0, delay - deviation)
setTimeout(() => {
callback()
loop()
}, nextDelay)
}
loop()
}
// 使用
customInterval(() => {
console.log('精準執行!')
}, 1000)
核心原理:
- 動態計算時間偏差(
deviation
) - 通過
nextDelay
自動修正延遲 - 誤差控制在 ±1ms 內,吊打原生 setInterval
三、進階騷操作:Web Worker + AbortController
1. 主線程零阻塞
將定時任務交給 Web Worker:
const worker = new Worker('timer-worker.js');
worker.postMessage({ type: 'start', delay: 1000 });
self.addEventListener('message', (e) => {
if (e.data.type === 'start') {
setInterval(() => {
self.postMessage('tick');
}, e.data.delay);
}
});
2. 優雅清除定時器
下面實現定時關閉:
function customSetTimeout(fn,time){
let timer = null;
function loop(){
timer = setTimeout(() => {
fn();
loop();
},time)
}
loop();
return () => clearTimeout(timer);
}
const tt= customSetTimeout(() => {
console.log("11111");
},1000);
setTimeout(() => {
tt();
},10000);
四、總結與靈魂拷問
三個必背知識點:
setInterval
誤差會累積,遞歸 setTimeout
才是王道- 定時器必須配合清除邏輯,否則內存泄漏分分鐘
- 復雜任務請交給 Web Worker,別折磨主線程
轉自https://juejin.cn/post/7481909735869235263
該文章在 2025/3/18 9:37:54 編輯過