無線頁面本就分秒必爭,更不用說當咱們在無線頁面中使用動畫的時候。不論是css動畫仍是canvas動畫,咱們都須要時刻當心着,而且有必要掌握頁面性能的基本分析方法。css
既然咱們的目標是優化,那麼就與瀏覽器的一些渲染和執行機制有關,更好的迎合瀏覽器的行爲方式,纔可讓咱們的動畫流暢而優美。html
沒錯,瀏覽器是老大,全聽它的。html5
咱們想讓頁面變快,想讓動畫流暢,咱們須要先了解一下是什麼在影響着咱們的感知。git
頁面運行在設備的瀏覽器中,如今市面上的移動設備的刷新頻率大可能是60次/秒(幀率)。因此給瀏覽器渲染每一幀的畫面的時間應該是(1s/60=16.67ms)。github
但實際上,瀏覽器並非把功夫全花在爲咱們渲染頁面上,他還須要作一些額外的工做,好比渲染隊列的管理和不一樣線程的切換等等。因此,單純的瀏覽器渲染工做留給咱們的時間大約也就是10ms左右,當咱們在每一幀所作的渲染操做大於這個時間的時候,比較直觀的表現就是頁面卡頓,動畫卡頓。web
當咱們使用css animation完成動畫時,這一點看起來沒有那麼重要,由於瀏覽器會爲咱們handle一些事情。可是當咱們須要使用js好比canvas來實現流暢的逐幀動畫時,須要牢記這個有限的時間,它很重要。chrome
咱們的代碼是如何一步步的渲染成頁面的呢?canvas
animate
函數作一個動畫、或者往頁面裏添加一些DOM元素等。固然,如今更可能的是使用CSS Animations, Transitions和Web Animation API。看起來每一個頁面都會經歷這樣的幾個過程,然而咱們其實可使用一些技巧,幫助瀏覽器跳過某些步驟,而縮短他的工做時間。瀏覽器
1.五個步驟都消耗了時間框架
當咱們在js中改變了某個DOM元素的layout時,那麼瀏覽器就會檢查頁面中的哪些元素須要從新佈局,而後對頁面激發一個reflow過程以完成頁面的從新佈局。被reflow的元素,接下來就必定會再次通過Paint和Composite這兩個過程,以渲染出最新的頁面。
2.跳過layout這一步
當咱們只修改了一個DOM元素的paint only屬性的時候,好比background-image/color/box-shadow等。這個時候不會觸發layout,瀏覽器在完成樣式的計算以後就會跳過layout的過程,就只Paint和Composite了。
3.跳過layout和paint這兩步
若是你修改一個非樣式且非繪製的CSS屬性,那麼瀏覽器會在完成樣式計算以後,跳過佈局和繪製的過程,直接Composite。
咱們嘗試下使用transform動畫來儘量的達到這種效果。
咱們可能常常須要作一些動畫,好比在作某些揭祕或者新手引導的效果時,會須要作一些將內容移入移出的操做。
固然可能第一個想到的就是 css transition 只要過渡一下 left 值或者 bottom 的值就能夠了。效果或許很快就會實現,可是當咱們在一個頁面頻繁的作着這樣的移入移出操做時,細心地咱們放在手機中(6P)看一看,動畫並不會很流暢,尤爲是在某些低端機型上。
咱們換用 transform 來實現相同的效果:
1 transition: left 2s ease-in-out; ---> transition: transform 2s ease-in-out; 2 left: xxx; ---> transform: translate3d(xxx, yyy, zzz);
緣由在於:
優化事後再放在設備裏查看,能夠感覺到效果明顯的提高。其實這裏就作到了上面提到的,節省了layout和paint。
如今css的動畫愈來愈好用,也能知足愈來愈多的需求。但在某些複雜的需求中咱們可能仍是要求助於js。
好比說我這裏實現的一個半圓的動畫:[半圓progress] [Source Code]。看起來使用css動畫就徹底能夠知足個人需求,可是當需求變化的時候,咱們也只能擁抱變化了。
**使用requestAnimationFrame**
[圓弧progress][Source Code] 這裏用canvas實現了自定義弧度圓弧的增加動畫。
這裏咱們藉助這個動畫效果看一下是如何使用canvas和requestAnimationFrame來實現流暢的逐幀動畫的。
window.requestAnimationFrame 是一個專門爲動畫而生的 web API 。它通知瀏覽器在頁面重繪前執行你的回調函數。一般來講被調用的頻率是每秒60次。
假設咱們的頁面上有一個動畫效果,若是咱們想保證每一幀的順利繪製,那麼咱們就須要requestAnimationFrame來保證咱們的繪製時機了。
不少框架和示例代碼都是用setTimeout
或setInterval
來實現頁面中的動畫效果,好比jQuery中的animation。這種實現方式的問題是,你在setTimeout
或setInterval
中指定的回調函數的執行時機是沒法保證的。它將在這一幀動畫的_某個時間點_被執行,極可能是在幀結束的時候。這就意味這咱們可能失去這一幀的信息。
**requestAnimationFrame的其餘高能用法**
根據requestAnimationFrame的特性,其實咱們還能夠在不少別的想不到的地方來一顯身手。
1 var $box = $('#J_Test'), 2 $point = $box.find('b'); 3 $box.on('mouseenter',function(e){ 4 requestAnimationFrame(function(){ 5 $point.css({ 6 top : e.pageY, 7 left : e.pageX 8 }) 9 }); 11 });
1 var rAF = window.requestAnimationFrame || window.webkitRequestAnimationFrame || 2 function(c) { 3 setTimeout(c, 1 / 60 * 1000); 4 }; 5 6 function render() { 7 self.$container.html(itemHtml); 8 self.$container.find('.J_LazyLoad').lazyload(); 9 } 10 11 rAF(render);
咱們仍是藉助這個例子,[圓弧progress][Source Code] 簡單的看下如何分析無線頁面的性能。
這裏的實現思路是這樣的:
1 - 肯定圓弧的起始弧度(0.75PI)和終止弧度(根據當前分值占上限分值的比例計算,最大爲2.25PI); 2 - 隨着時間的增加逐幀繪製終點位置 requestAnimationFrame(draw); 3 - 根據每一幀的終點位置的 cos 和 sin 值獲得跟隨的圓圈座標並繪製;
但固然,實現完成只是走了第一步,咱們來藉助Chrome Timeline來分析一下這個簡單的頁面。
使用Timeline就能夠看到頁面的幾種指標,幀率,js執行等等。就能夠針對出現問題的幀下手優化。
在分析頁面性能的時候,嚴重推薦閱讀:[https://developer.chrome.com/devtools/docs/timeline] .timeline的詳細使用說明,它真的很強大,能幫助咱們分析到頁面的各個方面的問題。