settimeout 引數_用setTimeout對比理解requestAnimationFrame
阿新 • • 發佈:2020-12-27
技術標籤:settimeout 引數
用setTimeout對比理解requestAnimationFrame
在H5標準出現之前,實現網頁動畫的方式無非就是 setTimeout
和 setInterval
,但這種方式弊端很多,最常見的就是佔用資源高造成卡頓現象。H5和CSS3出現之後,便出現了很多動畫的實現方式,如CSS3中的 transition
和 animation
,H5中的 canvas,還有一個比較常見但卻又是比較難理解的 requestAnimationFrame
,它的使用方法跟 setTimeout
和 setInterval
比較接近,所以接下來我們就會通過對比 setTimeout
setInterval
來認識 requestAnimationFrame
。
setTimeout
先上一段程式碼:
HTML:
<style> .block{ width: 100px; height: 100px; background-color: cyan; } </style> <body> <div class="block"></div> <script> var element = document.querySelector('.block'); element.style.position = 'absolute'; </script> <script src="./index.js"></script> </body>
JavaScript:
let left = 1;
function step(){
element.style.left = `${left++}px`;
let timer = setTimeout(() => {
step();
}, 1000/60);
if( timer && left > 100){
clearTimeout(timer)
}
}
step();
效果:
setTimeout
的方式實現動畫是不難理解的,首先JS主執行緒中執行一次 step()
函式,step()
step()
函式,直到達到100畫素。之所以用 1000/60 是因為瀏覽器的重新整理率是每秒鐘60Hz,也就是1000毫秒內重新整理60次,所以需要(1000/60ms)16.67ms執行一次動畫才能達到比較流暢的效果。看到這裡,似乎沒有理由使用除了 setTimeout
之外的東西實現動畫了,因為它表現的的確很流暢。但是,這是在理想的情況下,如果在 EventLoop 執行佇列執行 setTimeout
回撥函式之前有其他任務等待執行(現實的Web應用往往存在大量的任務在執行佇列等待執行),那麼 setTimeout
回撥就會延遲執行,直到執行佇列輪到 setTimeout
回撥,所以誰也不能保證 setTimeout
回撥一定是在16.67ms後執行的。這樣就會導致動畫不流暢,甚至卡頓的現象發生,所以有必要引入一個新的專門用於動畫的API,他就是 requestAnimationFrame
requestAnimationFrame
let left = 1;
function step() {
element.style.left = `${left}px`;
left *= 1.02;
if (left < 200) {
window.requestAnimationFrame(step);
}
}
window.requestAnimationFrame(step);
效果:
window.requestAnimationFrame()
告訴瀏覽器——你希望執行一個動畫,並且要求瀏覽器在下次重繪之前呼叫指定的回撥函式更新動畫。該方法需要傳入一個回撥函式作為引數,該回調函式會在瀏覽器下一次重繪之前執行
引自MDN —— window.requestAnimationFrame
requestAnimationFrame
的使用方法跟 setTimeout
區別不大,但是主要的區別是 requestAnimationFrame
的執行時機是瀏覽器去決定的,比如當前裝置重新整理率是60Hz,那它的執行就會是16.67ms。也可以說它的回撥函式的執行是與螢幕的重新整理有關,每刷完一次,就要執行一次,不會卡頓和掉幀。由於它定義的回撥是在下次重繪之前,所以必須在回撥裡再呼叫一次,才能實現連續的動畫。而且 requestAnimationFrame
在頁面隱藏掉或最小化的時候,是不會執行的,這樣就節省了一些不必要的系統資源。所以使用 requestAnimationFrame
比 setTimeout
好處要多。