在用js寫動畫的時候,無非使用 setTimeout/setInterval 或者 requestAnimationFrame 來處理動畫(在jquery的代碼裡也是這麼幹的),本文主要為了記錄下兩者的差別及使用兩者來實作動過程。
以實作一個簡單的滾動到頂部為例
setInterval
setInterval() 方法重複調用一個函數或執行一個代碼段,在每次調用之間具有固定的時間延遲。傳回一個intervalID,可用于 cancelInterval 達到結束循環的效果。
setTimeout 和 setInterval 的實作基本沒差別,一個是定時執行,一個是定時循環執行,前者加個自己調用自己就是後者了,下面主要以 setInterval 為代表
實作過程:
1.寫個方法,該方法需要傳入一個代表動畫所需執行的時間的參數(如:滾動到頂部需要1000毫秒)
2.取目前頁面距頂部高度、滾動速度(以勻速為例)、寫個開始動畫的函數(為了給addEventListener綁事件傳參,其實也可直接 dom.onclick = fn )
3.寫滾動動畫
4.寫個很高的頁面、給個div、加個click事件觸發滾動回頂部
html
js
效果如圖:

截圖分别測了設定 duration 為1000和3000的滾動效果
requestAnimationFrame
requestAnimationFrame() 方法告訴浏覽器您希望執行動畫,并請求浏覽器調用指定的函數在下一次重繪之前更新動畫。該方法将在重繪之前調用的回調作為參數。傳回一個 requestID ,可用于 cancelAnimationFrame 達到取消 requestAnimationFrame 動畫的效果。
實作思路如上,代碼如下:
沒差別,沒毛病,然而并沒有和上面用同一張圖...(其實列印下時間,會發現 setInterval 會是1000毫秒以内,大緻在960-980毫秒之間,這個梗哪位大神可知???求解!!!)
兩者的差別
requestAnimationFrame 會請求浏覽器調用指定的函數在下一次重繪之前更新動畫,是以開發者不用考慮頻率/丢幀問題
setInterval 中,會因為浏覽器顯示頻率和 JavaScript 單線程可能會引發阻塞的問題而導緻丢幀(視覺應為動畫不流暢)
requestAnimationFrame 會把每一幀中的所有 DOM 操作集中起來,在一次重繪或回流中就完成,性能方面更出色
對于隐藏或者不可見的元素,requestAnimationFrame 将不會進行重繪或回流,這點可減少cpu,gpu及記憶體的負荷
setInterval 相容一些老版本的浏覽器(jquery保留這個應該也是為了相容老版本浏覽器...)
requestAnimationFrame 相容圖
順便扔上jquery裡animate的部分代碼:
略顯尴尬... 在我windows上和mac上也保留一些老版本的浏覽器,測效果的結果簡直蛋疼...看來相容方面還是需要做處理的,天将降大任于 setInterval 啊 :-D
歡迎交流 歡迎指出各個問題~