無線頁面本就分秒必爭,更不用說當咱們在無線頁面中使用動畫的時候。不論是css動畫仍是canvas動畫,咱們都須要時刻當心着,而且有必要掌握頁面性能的基本分析方法。css
既然咱們的目標是優化,那麼就與瀏覽器的一些渲染和執行機制有關,更好的迎合瀏覽器的行爲方式,纔可讓咱們的動畫流暢而優美。html
沒錯,瀏覽器是老大,全聽它的。git
咱們想讓頁面變快,想讓動畫流暢,咱們須要先了解一下是什麼在影響着咱們的感知。github
頁面運行在設備的瀏覽器中,如今市面上的移動設備的刷新頻率大可能是60次/秒(幀率)。因此給瀏覽器渲染每一幀的畫面的時間應該是(1s/60=16.67ms)。web
但實際上,瀏覽器並非把功夫全花在爲咱們渲染頁面上,他還須要作一些額外的工做,好比渲染隊列的管理和不一樣線程的切換等等。因此,單純的瀏覽器渲染工做留給咱們的時間大約也就是10ms左右,當咱們在每一幀所作的渲染操做大於這個時間的時候,比較直觀的表現就是頁面卡頓,動畫卡頓。chrome
當咱們使用css animation完成動畫時,這一點看起來沒有那麼重要,由於瀏覽器會爲咱們handle一些事情。可是當咱們須要使用js好比canvas來實現流暢的逐幀動畫時,須要牢記這個有限的時間,它很重要。canvas
咱們的代碼是如何一步步的渲染成頁面的呢?瀏覽器
JavaScript。通常來講,咱們使用JavaScript來實現一些頁面邏輯,但偶爾咱們也可能會使用JavaScript來實現一些視覺變化的效果。好比用jQuery的animate函數作一個動畫、或者往頁面裏添加一些DOM元素等。固然,如今更可能的是使用CSS Animations, Transitions和Web Animation API。框架
計算樣式(Style)。這個過程是經過樣式文件中的CSS選擇器,對每一個DOM元素匹配對應的CSS樣式。函數
佈局(Layout)。上一步肯定了每一個DOM元素的樣式規則,這一步就是具體計算每一個DOM元素最終在屏幕上顯示的大小和位置。web頁面中元素的佈局是相對的,所以一個元素的佈局發生變化,會聯動地引起其餘元素的佈局發生變化。所以對於瀏覽器來講,佈局過程是常常發生的。
繪製(Paint)。繪製,本質上就是填充像素的過程。包括繪製文字、顏色、圖像、邊框和陰影等,也就是一個DOM元素全部的可視效果。通常來講,這個繪製過程是在多個層上完成的。
渲染層合併(Composite)。由上一步可知,對頁面中DOM元素的繪製是在多個層上進行的。在每一個層上完成繪製過程以後,瀏覽器會將全部層按照合理的順序合併成一個圖層,而後顯示在屏幕上。對於有位置重疊的元素的頁面,這個過程尤爲重要,由於一旦圖層的合併順序出錯,將會致使元素顯示異常。
看起來每一個頁面都會經歷這樣的幾個過程,然而咱們其實可使用一些技巧,幫助瀏覽器跳過某些步驟,而縮短他的工做時間。
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);
緣由在於:
簡單的說頁面的繪製並非在單層的畫面裏完成的,這其中有渲染層合成層等概念。對 opacity 和 transform 應用了 CSS 動畫的渲染層、有 3D 或者 perspective transform 的 CSS 屬性的渲染層等知足一些條件的渲染層被稱爲合成層;
合成層有本身的渲染上下文,而且交由 GPU 處理,比 CPU 要快;
當頁面須要重繪時,合成層的元素只會重繪本身層內的元素,而非整個頁面;
優化事後再放在設備裏查看,能夠感覺到效果明顯的提高。其實這裏就作到了上面提到的,節省了layout和paint。
如今css的動畫愈來愈好用,也能知足愈來愈多的需求。但在某些複雜的需求中咱們可能仍是要求助於js。
好比說我這裏實現的一個半圓的動畫:半圓progress。看起來使用css動畫就徹底能夠知足個人需求,可是當需求變化的時候,咱們也只能擁抱變化了。
使用requestAnimationFrame
圓弧progress這裏用canvas實現了自定義弧度圓弧的增加動畫。
這裏咱們藉助這個動畫效果看一下是如何使用canvas和requestAnimationFrame來實現流暢的逐幀動畫的。
window.requestAnimationFrame 是一個專門爲動畫而生的 web API 。它通知瀏覽器在頁面重繪前執行你的回調函數。一般來講被調用的頻率是每秒60次。
假設咱們的頁面上有一個動畫效果,若是咱們想保證每一幀的順利繪製,那麼咱們就須要requestAnimationFrame來保證咱們的繪製時機了。
不少框架和示例代碼都是用setTimeout或setInterval來實現頁面中的動畫效果,好比jQuery中的animation。這種實現方式的問題是,你在setTimeout或setInterval中指定的回調函數的執行時機是沒法保證的。它將在這一幀動畫的_某個時間點_被執行,極可能是在幀結束的時候。這就意味這咱們可能失去這一幀的信息。
requestAnimationFrame的其餘高能用法
根據requestAnimationFrame的特性,其實咱們還能夠在不少別的想不到的地方來一顯身手。
動畫:也是它的主要用途,它將咱們動畫的執行時機和執行頻率交由瀏覽器決定,以獲得更好的性能;
函數節流:requestAnimationFrame 的執行頻率(一幀)是16.67ms,利用這一個特徵就能夠作到函數節流,避免高頻事件在一幀內作多餘的無用功的函數執行,例:
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 });
分幀初始化:一樣利用一幀的執行時間將模塊的初始化或渲染函數分散到不一樣的幀中來執行,這樣每一個模塊都有16.67ms的執行時間,而不是一股腦的堆在那裏等着執行;
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 簡單的看下如何分析無線頁面的性能。
這裏的實現思路是這樣的:
肯定圓弧的起始弧度(0.75PI)和終止弧度(根據當前分值占上限分值的比例計算,最大爲2.25PI);
隨着時間的增加逐幀繪製終點位置 requestAnimationFrame(draw);
根據每一幀的終點位置的 cos 和 sin 值獲得跟隨的圓圈座標並繪製;
但固然,實現完成只是走了第一步,咱們來藉助Chrome Timeline來分析一下這個簡單的頁面。
看一下幀率,在進度動畫進行的時候,看起來幀率不錯,沒有產生掉幀的現象,說明每一幀的耗時都還ok,個人動畫基本不會卡頓;
在函數的執行和調用那一欄中,可能有問題的部分右上角會被標紅,還能夠查看可能存在問題的細節;這裏提示我頁面強制重排了,仔細觀察下面的 Bottom-up tab 中能夠定位到具體的代碼。
使用Timeline就能夠看到頁面的幾種指標,幀率,js執行等等。就能夠針對出現問題的幀下手優化。
在分析頁面性能的時候,嚴重推薦閱讀:[https://developer.chrome.com/devtools/docs/timeline] .timeline的詳細使用說明,它真的很強大,能幫助咱們分析到頁面的各個方面的問題。