以往JS控制的動畫大多使用setInterval
或者setTimeout
每隔一段時間刷新元素的位置,來達到動畫的效果,可是這種方式並不能準確地控制動畫幀率,儘管主流的瀏覽器對於這兩個函數實現的動畫都有必定的優化,可是這依然沒法彌補它們性能問題。主要緣由是由於JavaScript的單線程機制使得其可能在有阻塞的狀況下沒法精確到毫秒觸發。css
requestAnimationFrame()
方法正是爲了知足高性能動畫的需求而提供的API,經過setInterval
方法控制的動畫其調用的間隔由程序員設置,而requestAnimationFrame()
無須設置調用間隔, 它自動緊跟瀏覽器的繪製的幀率(通常瀏覽器的顯示幀率是60fps,差很少每幀間隔16.7ms)html
關於過去的setInterval
控制的動畫與requestAnimationFrame()
的效果的對比,這裏引用‘艾倫’的帖子中的栗子。原帖地址?動畫requestAnimationFramecss3
setInterval動畫DEMO
requestAnimationFrame動畫DEMO程序員
點擊預覽以上兩個demo能夠明顯感覺到前者有點卡頓,後者更爲流暢。web
另外requestAnimationFrame()
在隱藏或不可見的元素中將不會進行重繪或迴流,大大下降了開銷。關於該方法的其餘細節見MDN文檔? window.requestAnimationFrame瀏覽器
以上都是廢話,多寫才能體會。這裏我嘗試用該方法寫了個晃動動畫(點擊黑盒晃動,我的練習並無考慮兼容性):wordpress
動畫練習DEMO函數
JS代碼:性能
//從網頁中獲取一個元素 var box = document.getElementById('box') shake(box, 500, 15) //接受三個參數:動畫元素,持續時間,晃動距離 function shake(elm, dur, distance) { if (elm) { var dur = dur || 500 var distance = distance || 10 //保存原樣式 var original_css = elm.style.cssText elm.addEventListener('click', ani, false) } else { return 'no param' } function ani() { var start = null requestAnimationFrame(act) //requestAnimationFrame每次調用向callback中傳入一個時間戳,時間戳爲每次調用的時間點 function act(time_stamp) { if(start === null) start = time_stamp var elapsed = time_stamp - start if ((elapsed / dur) < 1) { //乘以4PI,來回往復兩次, 使用正弦函數獲得比例 elm.style.transform = 'translateX(' + distance * Math.sin((elapsed / dur) * 4 * Math.PI) + 'px' + ')' //調用該方法將返回一個ID值用於結束調用 var time_id = requestAnimationFrame(act) } else { //恢復原樣式,中止動畫 elm.style.cssText = original_css cancelAnimationFrame(time_id) } } } }
在實際開發中, 固然儘可能使用css動畫, 畢竟css動畫性能更優。可是對於一些複雜的動畫,好比有暫停,繼續等複雜交互等動畫仍是須要requestAnimationFrame
,在張鑫旭大神的這篇文章中CSS3動畫那麼強,requestAnimationFrame還有毛線用? 深刻淺出的闡釋了該方法, 另外他的demo中也有一個很直觀的栗子? 優化
該方法其餘參考資料mark下:
性能更好的js動畫實現方式——requestAnimationFrame
HTML5探祕:用requestAnimationFrame優化Web動畫