【面試】JS實現動畫之setTimeout、setInterval和requestAnimationFrame

參考:《JS高級程序設計》,這篇requestAnimationFrame文章javascript

JS實現動畫主要有三種方式:setTimeoutsetIntervalrequestAnimationFrame。其中最後一種方法比較好。html

setTimeoutsetInterval

setTimeoutsetInterval能夠用來建立定時器。定時器對隊列的工做方式是,當特定時間過去後將代碼插入。java

定時器指定的時間間隔表示什麼時候將定時器的代碼添加到隊列,而不是什麼時候實際執行代碼!瀏覽器

setInterval

一個用setInterval實現的進度條例子函數

<div id="myDiv" style="background-color: lightblue;width: 0;height: 20px;line-height: 20px;">0%</div>
<button id="btn">run</button>

<script> var timer; btn.onclick = function(){ // 取消對應的定時器,注意與clearTimeout不同 clearInterval(timer); // 注意是字符串,給parseInt用 myDiv.style.width = '0'; timer = setInterval(function(){ // parseInt解析一個字符串,返回一個整數 if(parseInt(myDiv.style.width) < 500){ myDiv.style.width = parseInt(myDiv.style.width) + 5 + 'px'; // 總長500,除以5的數字正好是百分比 myDiv.innerHTML = parseInt(myDiv.style.width)/5 + '%'; }else{ clearInterval(timer); } },16); } </script>

複製代碼

setInterval確保了定時器代碼規則地插入隊列中(注意不是規則的執行)。優化

當定時器代碼要插入隊列時,已經有一個定時器代碼 正在運行,而且有一個 定時器實例 在等待,則此處不插入,跳過。 確保定時器代碼加入到隊列中的最小時間間隔爲指定間隔(實際間隔有可能大於指定間隔)。動畫

缺點:ui

  • 某些間隔被跳過
  • 多個定時器代碼執行之間的間隔可能比預期的小

setTimeout

調用鏈式setTimeout能夠避免上述兩個缺點,每次函數執行的時候都會建立換一個新的定時器。在前一個定時器代碼執行完以前,不會向隊列插入新的定時器代碼,確保不會有任何確實的間隔。而且確保在下一次定時器代碼執行以前,至少要等待指定的間隔,避免了連續的運行。spa

一個用setTimeout實現進度條的例子設計

<div id="myDiv" style="background-color: lightblue;width: 0;height: 20px;line-height: 20px;">0%</div>
<button id="btn">run</button>
<script> var timer; btn.onclick = function() { // 注意與clearInterval不同 clearTimeout(timer); myDiv.style.width = '0'; // 給function取個名字後面鏈式用 timer = setTimeout(function fn(){ if(parseInt(myDiv.style.width) < 500) { myDiv.style.width = parseInt(myDiv.style.width) + 5 + 'px'; myDiv.innerHTML = parseInt(myDiv.style.width)/5 + '%'; // 鏈式setTimeout timer = setTimeout(fn,16); } else { clearTimeout(timer); } },16) } </script>
複製代碼

requestAnimationFrame

requestAnimationFrame實現的進度條例子

<div id="myDiv" style="background-color: lightblue;width: 0;height: 20px;line-height: 20px;">0%</div>
<button id="btn">run</button>
<script> var timer; btn.onclick = function(){ // 注意cancelAnimationFrame cancelAnimationFrame(timer); myDiv.style.width = '0'; timer = requestAnimationFrame(function fn(){ if(parseInt(myDiv.style.width) < 500) { myDiv.style.width = parseInt(myDiv.style.width) + 5 + 'px'; myDiv.innerHTML = parseInt(myDiv.style.width)/5 + '%'; // requestAnimationFrame只傳入一個參數 timer = requestAnimationFrame(fn); } else { cancelAnimationFrame(timer); } }) // 只傳入一個參數 } </script>

複製代碼

最大區別:採用系統時間間隔,最佳繪製。使用一個回調函數做爲參數,這個回調函數會在瀏覽器重繪以前調用。

【1】requestAnimationFrame會把每一幀中的全部DOM操做集中起來,在一次重繪或迴流中就完成,而且重繪或迴流的時間間隔牢牢跟隨瀏覽器的刷新頻率

【2】在隱藏或不可見的元素中,requestAnimationFrame將不會進行重繪或迴流,這固然就意味着更少的CPU、GPU和內存使用量

【3】requestAnimationFrame是由瀏覽器專門爲動畫提供的API,在運行時瀏覽器會自動優化方法的調用,而且若是頁面不是激活狀態下的話,動畫會自動暫停,有效節省了CPU開銷

相關文章
相關標籤/搜索