setTimeout、setInterval、requestAnimationFrame 各有什么特點?


異步編程當然少不了定時器了,常見的定時器函數有setTimeoutsetIntervalrequestAnimationFrame。我們先來講講最常用的setTimeout,很多人認為setTimeout是延時多久,那就應該是多久后執行。

其實這個觀點是錯誤的,因為 JS 是單線程執行的,如果前面的代碼影響了性能,就會導致setTimeout不會按期執行。當然了,我們可以通過代碼去修正setTimeout,從而使定時器相對准確

let period = 60 * 1000 * 60 * 2 let startTime = new Date().getTime() let count = 0 let end = new Date().getTime() + period let interval = 1000 let currentInterval = interval function loop() { count++ // 代碼執行所消耗的時間 let offset = new Date().getTime() - (startTime + count * interval); let diff = end - new Date().getTime() let h = Math.floor(diff / (60 * 1000 * 60)) let hdiff = diff % (60 * 1000 * 60) let m = Math.floor(hdiff / (60 * 1000)) let mdiff = hdiff % (60 * 1000) let s = mdiff / (1000) let sCeil = Math.ceil(s) let sFloor = Math.floor(s) // 得到下一次循環所消耗的時間 currentInterval = interval - offset console.log('時:'+h, '分:'+m, '毫秒:'+s, '秒向上取整:'+sCeil, '代碼執行時間:'+offset, '下次循環間隔'+currentInterval) setTimeout(loop, currentInterval) } setTimeout(loop, currentInterval) 

接下來我們來看setInterval,其實這個函數作用和setTimeout基本一致,只是該函數是每隔一段時間執行一次回調函數。
通常來說不建議使用setInterval。第一,它和setTimeout一樣,不能保證在預期的時間執行任務。第二,它存在執行累積的問題,請看以下偽代碼

function demo() { setInterval(function(){ console.log(2) },1000) sleep(2000) } demo() 

以上代碼在瀏覽器環境中,如果定時器執行過程中出現了耗時操作,多個回調函數會在耗時操作結束以后同時執行,這樣可能就會帶來性能上的問題。
如果你有循環定時器的需求,其實完全可以通過requestAnimationFrame來實現

function setInterval(callback, interval) { let timer const now = Date.now let startTime = now() let endTime = startTime const loop = () => { timer = window.requestAnimationFrame(loop) endTime = now() if (endTime - startTime >= interval) { startTime = endTime = now() callback(timer) } } timer = window.requestAnimationFrame(loop) return timer } let a = 0 setInterval(timer => { console.log(1) a++ if (a === 3) cancelAnimationFrame(timer) }, 1000) 

首先requestAnimationFrame自帶函數節流功能,基本可以保證在 16.6 毫秒內只執行一次(不掉幀的情況下),並且該函數的延時效果是精確的,沒有其他定時器時間不准的問題,當然你也可以通過該函數來實現setTimeout


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM