PC 端優化的策略不少,如 YSlow(YSlow 是 Yahoo 發佈的一款 Firefox 插件,現 Chrome 也可安裝,能夠對網站的頁面性能進行分析,提出對該頁面性能優化的建議)原則,或者 Chrome 自帶的 Audits 等,總結起來主要包括網絡加載類、頁面渲染類、CSS 優化類、JavaScript 執行類、緩存類、圖片類、架構協議類等幾類,下面逐一介紹。javascript
在前端頁面中,一般建議儘量合併靜態資源圖片、JavaScript 或 CSS 代碼,減小頁面請求數和資源請求消耗,這樣能夠縮短頁面首次訪問的用戶等待時間。經過構建工具合併雪碧圖、CSS、JavaScript 文件等都是爲了減小 HTTP 資源請求次數。另外也要儘可能避免重複的資源,防止增長多餘請求。css
除了減小 HTTP 資源請求次數,也要儘可能減少每一個 HTTP 請求的大小。如減小不必的圖片、JavaScript、CSS 及 HTML 代碼,對文件進行壓縮優化,或者使用 gzip 壓縮傳輸內容等均可以用來減少文件大小,縮短網絡傳輸等待時延。前面咱們使用構建工具來壓縮靜態圖片資源以及移除代碼中的註釋並壓縮,目的都是爲了減少 HTTP 請求的大小。html
<style>
或 <script>
標籤直接引入在 HTML 文件中引用外部資源能夠有效利用瀏覽器的靜態資源緩存,但有時候在移動端頁面 CSS 或 JavaScript 比較簡單的狀況下爲了減小請求,也會將 CSS 或 JavaScript 直接寫到 HTML 裏面,具體要根據 CSS 或 JavaScript 文件的大小和業務的場景來分析。若是 CSS 或 JavaScript 文件內容較多,業務邏輯較複雜,建議放到外部文件引入。前端
<link rel="stylesheet" href="//cdn.domain.com/path/main.css" >
java
...
web
<script src="//cdn.domain.com/path/main.js"></script>
ajax
當 <link>
標籤的 href 屬性爲空,或 <script>
、 <img>
、 <iframe>
標籤的 src 屬性爲空時,瀏覽器在渲染的過程當中仍會將 href 屬性或 src 屬性中的空內容進行加載,直至加載失敗,這樣就阻塞了頁面中其餘資源的下載進程,並且最終加載到的內容是無效的,所以要儘可能避免。編程
<!--不推薦-->
後端
<img src="" alt="photo" >
跨域
<a href="">點擊連接</a>
爲 HTML 內容設置 Cache-Control 或 Expires 能夠將 HTML 內容緩存起來,避免頻繁向服務器端發送請求。前面講到,在頁面 Cache-Control 或 Expires 頭部有效時,瀏覽器將直接從緩存中讀取內容,不向服務器端發送請求。
<meta http-equiv="Cache-Control" content="max-age=7200">
<meta http-equiv="Expires" content="Mon,20Jul201623:00:00GMT">
合理設置 Etag 和 Last-Modified 使用瀏覽器緩存,對於未修改的文件,靜態資源服務器會向瀏覽器端返回 304,讓瀏覽器從緩存中讀取文件,減小 Web 資源下載的帶寬消耗並下降服務器負載。
<meta http-equiv="last-modified" content="Sun,05 Nov 2017 13:45:57 GMT">
頁面每次重定向都會延長頁面內容返回的等待延時,一次重定向大約須要 200 毫秒不等的時間開銷(無緩存),爲了保證用戶儘快看到頁面內容,要儘可能避免頁面重定向。
瀏覽器在同一時刻向同一個域名請求文件的並行下載數是有限的,所以能夠利用多個域名的主機來存放不一樣的靜態資源,增大頁面加載時資源的並行下載數,縮短頁面資源加載的時間。一般根據多個域名來分別存儲 JavaScript、CSS 和圖片文件。
<link rel="stylesheet" href="//cdn1.domain.com/path/main.css" >
...
<script src="//cdn2.domain.com/path/main.js"></script>
若是條件容許,能夠利用 CDN 網絡加快同一個地理區域內重複靜態資源文件的響應下載速度,縮短資源請求時間。
CDN Combo 是在 CDN 服務器端將多個文件請求打包成一個文件的形式來返回的技術,這樣能夠實現 HTTP 鏈接傳輸的一次性複用,減小瀏覽器的 HTTP 請求數,加快資源下載速度。例如同一個域名 CDN 服務器上的 a.js,b.js,c.js 就能夠按以下方式在一個請求中下載。
<script src="//cdn.domain.com/path/a.js,b.js,c.js"></script>
對於返回內容相同的請求,不必每次都直接從服務端拉取,合理使用 AJAX 緩存能加快 AJAX 響應速度並減輕服務器壓力。
$.ajax({
url : url,
type : 'get',
cache : true, //推薦使用緩存
data : {},
success (){//...},
error (){//...}
});
使用 XMLHttpRequest 時,瀏覽器中的 POST 方法會發起兩次 TCP 數據包傳輸,首先發送文件頭,而後發送 HTTP 正文數據。而使用 GET 時只發送頭部,因此在拉取服務端數據時使用 GET 請求效率更高。
$.ajax({
url : url,
type : 'get', //推薦使用get完成請求
data : {},
success (){//...},
error(){//...}
});
HTTP 請求一般默認帶上瀏覽器端的 Cookie 一塊兒發送給服務器,因此在非必要的狀況下,要儘可能減小 Cookie 來減少 HTTP 請求的大小。對於靜態資源,儘可能使用不一樣的域名來存放,由於 Cookie 默認是不能跨域的,這樣就作到了不一樣域名下靜態資源請求的 Cookie 隔離。
有利於 favicon.ico 的重複加載,由於通常一個 Web 應用的 favicon.ico 是不多改變的。
異步的 JavaScript 資源不會阻塞文檔解析,因此容許在瀏覽器中優先渲染頁面,延後加載腳本執行。例如 JavaScript 的引用能夠以下設置,也可使用模塊化加載機制來實現。
<script src="main.js" defer></script>
<script src="main.js" async></script>
使用 async 時,加載和渲染後續文檔元素的過程和 main.js 的加載與執行是並行的。使用 defer 時,加載後續文檔元素的過程和 main.js 的加載是並行的,可是 main.js 的執行要在頁面全部元素解析完成以後纔開始執行。
對於頁面中加載時間過長的 CSS 或 JavaScript 文件,須要進行合理拆分或延後加載,保證關鍵路徑的資源能快速加載完成。
CSS 中的 @import
能夠從另外一個樣式文件中引入樣式,但應該避免這種用法,由於這樣會增長 CSS 資源加載的關鍵路徑長度,帶有 @import
的 CSS 樣式須要在 CSS 文件串行解析到 @import
時纔會加載另外的 CSS 文件,大大延後 CSS 渲染完成的時間。
<!--不推薦-->
<style>
@import "path/main.css";
</style>
<!--推薦-->
<link rel="stylesheet" href="//cdn1.domain.com/path/main.css" >
通常推薦將全部 CSS 資源儘早指定在 HTML 文檔 <head>
中,這樣瀏覽器能夠優先下載 CSS 並儘早完成頁面渲染。
JavaScript 資源放到 HTML 文檔底部能夠防止 JavaScript 的加載和解析執行對頁面渲染形成阻塞。因爲 JavaScript 資源默認是解析阻塞的,除非被標記爲異步或者經過其餘的異步方式加載,不然會阻塞 HTML DOM 解析和 CSS 渲染的過程。
在加載大量的圖片元素時,儘可能預先限定圖片的尺寸大小,不然在圖片加載過程當中會更新圖片的排版信息,產生大量的重排
在 HTML 中直接縮放圖片會致使頁面內容的重排重繪,此時可能會使頁面中的其餘操做產生卡頓,所以要儘可能減小在頁面中直接進行圖片縮放。
HTML 中標籤元素越多,標籤的層級越深,瀏覽器解析 DOM 並繪製到瀏覽器中所花的時間就越長,因此應儘量保持 DOM 元素簡潔和層級較少。
<!--不推薦-->
<div>
<span>
<a href="javascript:void(0);">
<img src="./path/photo.jpg" alt="圖片">
</a>
</span>
</div>
<!--推薦-->
<img src="./path/photo.jpg" alt="圖片" >
CSS 解析匹配到 渲染樹的過程是從右到左的逆向匹配,在選擇器末尾添加通配符至少會增長一倍多計算量。
直接使用惟一的類名便可最大限度的提高渲染引擎繪製渲染樹等效率
JS 直接操做 DOM 極容易引發頁面的重排
儘可能使用 CSS3 的 translate、scale 屬性代替 top、left 和 height、width,避免大量的重排計算
<table>
、 <iframe>
<table>
內容的渲染是將 table 的 DOM 渲染樹所有生成完並一次性繪製到頁面上的,因此在長表格渲染時很耗性能,應該儘可能避免使用它,能夠考慮使用列表元素 <ul>
代替。儘可能使用異步的方式動態添加 iframe,由於 iframe 內資源的下載進程會阻塞父頁面靜態資源的下載與 CSS 及 HTML DOM 的解析。
長時間運行的 JavaScript 會阻塞瀏覽器構建 DOM 樹、DOM 渲染樹、渲染頁面。因此,任何與頁面初次渲染無關的邏輯功能都應該延遲加載執行,這和 JavaScript 資源的異步加載思路是一致的。
CSS 表達式或 CSS 濾鏡的解析渲染速度是比較慢的,在有其餘解決方案的狀況下應該儘可能避免使用。
//不推薦
.opacity{
filter : progid : DXImageTransform.Microsoft.Alpha( opacity = 50 );
}
相對於桌面端瀏覽器,移動端 Web 瀏覽器上有一些較爲明顯的特色:設備屏幕較小、新特性兼容性較好、支持一些較新的 HTML5 和 CSS3 特性、須要與 Native 應用交互等。但移動端瀏覽器可用的 CPU 計算資源和網絡資源極爲有限,所以要作好移動端 Web 上的優化每每須要作更多的事情。首先,在移動端 Web 的前端頁面渲染中,桌面瀏覽器端上的優化規則一樣適用,此外針對移動端也要作一些極致的優化來達到更好的效果。須要注意的是,並非移動端的優化原則在桌面瀏覽器端就不適用,而是因爲兼容性和差別性的緣由,一些優化原則在移動端更具表明性。
爲了進一步提高頁面加載速度,能夠考慮將頁面的數據請求儘量提早,避免在 JavaScript 加載完成後纔去請求數據。一般數據請求是頁面內容渲染中關鍵路徑最長的部分,並且不能並行,因此若是能將數據請求提早,能夠極大程度上縮短頁面內容的渲染完成時間。
因爲移動端網絡速度相對較慢,網絡資源有限,所以爲了儘快完成頁面內容的加載,須要保證首屏加載資源最小化,非首屏內容使用滾動的方式異步加載。通常推薦移動端頁面首屏數據展現延時最長不超過 3 秒。目前中國聯通 3G 的網絡速度爲 338KB/s(2.71Mb/s),因此推薦首屏全部資源大小不超過 1014KB,即大約不超過 1MB。
在移動端資源加載中,儘可能保證 JavaScript 資源並行加載,主要指的是模塊化 JavaScript 資源的異步加載,例如 AMD 的異步模塊,使用並行的加載方式可以縮短多個文件資源的加載時間。
一般爲了在 HTML 加載完成時能使瀏覽器中有基本的樣式,須要將頁面渲染時必備的 CSS 和 JavaScript 經過 <script>
或 <style>
內聯到頁面中,避免頁面 HTML 載入完成到頁面內容展現這段過程當中頁面出現空白。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>樣例</title>
<meta >
<style>
/*必備的首屏CSS*/
html,body{
margin:0;
padding:0;
background-color:#ccc;
}
</style>
</head>
<body>
</body>
</html>
設置文件資源的 DNS 預解析,讓瀏覽器提早解析獲取靜態資源的主機 IP,避免等到請求時才發起 DNS 解析請求。一般在移動端 HTML 中能夠採用以下方式完成。
<!--cdn域名預解析-->
<meta http-equiv="x-dns-prefetch-control" content="on" >
<link rel="dns-prefetch" href="//cdn.domain.com" >
對於移動端首屏加載後可能會被使用的資源,須要在首屏完成加載後儘快進行加載,保證在用戶須要瀏覽時已經加載完成,這時候若是再去異步請求就顯得很慢。
一般狀況下,咱們認爲 TCP 網絡傳輸的最大傳輸單元(Maximum Transmission Unit,MTU)爲 1500B,即一個 RTT(Round-Trip Time,網絡請求往返時間)內能夠傳輸的數據量最大爲 1500 字節。所以,在先後端分離的開發模式中,儘可能保證頁面的 HTML 內容在 1KB 之內,這樣整個 HTML 的內容請求就能夠在一個 RTT 內請求完成,最大限度地提升 HTML 載入速度。
除了上面說到的使用 Cache-Control、Expires、Etag 和 Last-Modified 來設置 HTTP 緩存外,在移動端還可使用 localStorage 等來保存 AJAX 返回的數據,或者使用 localStorage 保存 CSS 或 JavaScript 靜態資源內容,實現移動端的離線應用,儘量減小網絡請求,保證靜態資源內容的快速加載。
對於移動端或 Hybrid 應用,能夠設置離線文件或離線包機制讓靜態資源請求從本地讀取,加快資源載入速度,並實現離線更新。關於這塊內容,咱們會在後面的章節中重點講解。
AMP HTML 能夠做爲優化前端頁面性能的一個解決方案,使用 AMP Component 中的元素來代替原始的頁面元素進行直接渲染。
<!--不推薦-->
<video width="400" height="300" src="http://www.domain.com/videos/myvideo.mp4"
poster="path/poster.jpg">
<div fallback>
<p>Your browser doesn’t support HTML5 video</p>
</div>
<source type="video/mp4" src="foo.mp4">
<source type="video/webm" src="foo.webm">
</video>
<!--推薦-->
<amp-video width="400" height="300" src="http://www.domain.com/videos/myvideo.mp4"
poster="path/poster.jpg">
<div fallback>
<p>Your browser doesn’t support HTML5 video</p>
</div>
<source type="video/mp4" src="foo.mp4">
<source type="video/webm" src="foo.webm">
</amp-video>
PWA(Progressive Web Apps)是 Google 提出的用前沿的 Web 技術爲網頁提供 App 般使用體驗的一系列方案。
在移動端,一般要保證頁面中一切用到的圖片都是通過壓縮優化處理的,而不是以原圖的形式直接使用的,由於那樣很消耗流量,並且加載時間更長。
在頁面使用的背景圖片很少且較小的狀況下,能夠將圖片轉化成 base64 編碼嵌入到 HTML 頁面或 CSS 文件中,這樣能夠減小頁面的 HTTP 請求數。須要注意的是,要保證圖片較小,通常圖片大小超過 2KB 就不推薦使用 base64 嵌入顯示了。
.class-name{
background-image : url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAALCAMAAABxsOwqAAAAYFBMVEWnxwusyQukxQudwQyZvgyhxAyfwgyxzAsUHQGOuA0aJAERGAFIXwSTugyEqgtqhghQZgUwQQIpOQKbuguVtQuKrAuCowp2kQlheghTbQZHWQU7SwVAVgQ6TgQlLwMeKwFOemyQAAAAVElEQVQI1y3JVRaAIAAF0UconXbvf5ei8HfPDIQQhBAAFE10iKig3SLRNN4SP/p+N08VC0YnfIlNWtqIkhg/TPYbCvhqdHAWRXPZSp3g3CWZvVLXC6OJA3ukv0AaAAAAAElFTkSuQmCC');
}
使用具備較高壓縮比格式的圖片,如 webp(須要設計降級兼容方案)等。在同等圖片畫質的狀況下,高壓縮比格式的圖片體積更小,可以更快完成文件傳輸,節省網絡流量。
<img src="//cdn.domain.com/path/photo.webp" alt="webp格式圖片" >
爲了保證頁面內容的最小化,加速頁面的渲染,儘量節省移動端網絡流量,頁面中的圖片資源推薦使用懶加載實現,在頁面滾動時動態載入圖片。
<img data-src="//cdn.domain.com/path/photo.jpg" alt="懶加載圖片" >
在介紹響應式的章節中咱們瞭解到,針對不一樣的移動端屏幕尺寸和分辨率,輸出不一樣大小的圖片或背景圖能保證在用戶體驗不下降的前提下節省網絡流量,加快部分機型的圖片加載速度,這在移動端很是值得推薦。
在頁面中儘量使用 iconfont 來代替圖片圖標,這樣作的好處有如下幾個:
使用 iconfont 體積較小,並且是矢量圖,所以縮放時不會失真;
能夠方便地修改圖片大小尺寸和呈現顏色。
可是須要注意的是,iconfont 引用不一樣 webfont 格式時的兼容性寫法,根據經驗推薦儘可能按照如下順序書寫,不然不容易兼容到全部的瀏覽器上。
@font-face{
font-family:iconfont;
src:url("./iconfont.eot");
src:url("./iconfont.eot?#iefix") format("eot"),
url("./iconfont.woff") format("woff"),
url("./iconfont.ttf") format("truetype");
}
加載的單張圖片通常建議不超過 30KB,避免大圖片加載時間長而阻塞頁面其餘資源的下載,所以推薦在 10KB 之內。若是用戶上傳的圖片過大,建議設置告警系統,幫助咱們觀察瞭解整個網站的圖片流量狀況,作出進一步的改善。
對於一些「永遠」不會變的圖片可使用強緩存的方式緩存在用戶的瀏覽器上。
選擇器選擇頁面 DOM 元素時儘可能使用 id 選擇器,由於 id 選擇器速度最快。
對於須要重複使用的 DOM 對象,要優先設置緩存變量,避免每次使用時都要從整個 DOM 樹中從新查找。
//不推薦
$('#mod.active').remove('active');
$('#mod.not-active').addClass('active');
//推薦
let $mod=$('#mod');
$mod.find('.active').remove('active');
$mod.find('.not-active').addClass('active');
使用事件代理能夠避免對每一個元素都進行綁定,而且能夠避免出現內存泄露及須要動態添加元素的事件綁定問題,因此儘可能不要直接使用事件綁定。
//不推薦
$('.btn').on('click',function(e){
console.log(this);
});
//推薦
$('body').on('click','.btn',function(e){
console.log(this);
});
因爲移動端屏幕的設計, touchstart 事件和 click 事件觸發時間之間存在 300 毫秒的延時,因此在頁面中沒有實現 touchmove 滾動處理的狀況下,可使用 touchstart 事件來代替元素的 click 事件,加快頁面點擊的響應速度,提升用戶體驗。但同時咱們也要注意頁面重疊元素 touch 動做的點擊穿透問題。
//不推薦
$('body').on('click','.btn',function(e){
console.log(this);
});
//推薦
$('body').on('touchstart','.btn',function(e){
console.log(this);
});
須要對 touchmove、scroll 這類可能連續觸發回調的事件設置事件節流,例如設置每隔 16ms(60 幀的幀間隔爲 16.7ms,所以能夠合理地設置爲 16ms )才進行一次事件處理,避免頻繁的事件調用致使移動端頁面卡頓。
//不推薦
$('.scroller').on('touchmove','.btn',function(e){
console.log(this);
});
//推薦
$('.scroller').on('touchmove','.btn',function(e){
let self=this;
setTimeout(function(){
console.log(self);
},16);
});
這些都是一些基礎的安全腳本編寫問題,儘量使用較高效率的特性來完成這些操做,避免不規範或不安全的寫法。
ECMAScript6+ 必定程度上更加安全高效,並且部分特性執行速度更快,也是將來規範的須要,因此推薦使用 ECMAScript6+ 的新特性來完成後面的開發。
通常認爲,在移動端設置 Viewport 能夠加速頁面的渲染,同時能夠避免縮放致使頁面重排重繪。在移動端固定 Viewport 設置的方法以下。
<!--設置viewport不縮放-->
<meta >
頁面的重排重繪很耗性能,因此必定要儘量減小頁面的重排重繪,例如頁面圖片大小變化、元素位置變化等這些狀況都會致使重排重繪。
使用 CSS3 動畫時能夠設置 transform:translateZ(0) 來開啓移動設備瀏覽器的 GPU 圖形處理加速,讓動畫過程更加流暢,但須要注意的是,在 Native WebView 下 GPU 加速有概率產生 App Crash。
-webkit-transform:translateZ(0);
-ms-transform:translateZ(0);
-o-transform:translateZ(0);
transform:translateZ(0);
選擇 Canvas 或 requestAnimationFrame 等更高效的動畫實現方式,儘可能避免使用 setTimeout、setInterval 等方式來直接處理連續動畫。
部分狀況下能夠考慮使用 SVG 代替圖片實現動畫,由於使用 SVG 格式內容更小,並且 SVG DOM 結構方便調整。
在 DOM 渲染樹生成後的佈局渲染階段,使用 float 的元素佈局計算比較耗性能,因此儘可能減小 float 的使用,推薦使用固定佈局或 flex-box 彈性佈局的方式來實現頁面元素佈局。
過多的 font-size 聲明會增長字體的大小計算,並且也沒有必要的。
腳本容錯能夠避免「非正常環境」的執行錯誤影響頁面的加載和不相關功能的使用
在條件容許的狀況下能夠考慮使用 SPDY 協議來進行文件資源傳輸,利用鏈接複用加快傳輸過程,縮短資源加載時間。HTTP2 在將來也是能夠考慮嘗試的。
使用後端數據渲染的方式能夠加快頁面內容的渲染展現,避免空白頁面的出現,同時能夠解決移動端頁面 SEO 的問題。若是條件容許,後端數據渲染是一個很不錯的實踐思路。後面的章節會詳細介紹後端數據渲染的相關內容。
能夠嘗試使用 NativeView 的 MNV* 開發模式來避免 HTML DOM 性能慢的問題,目前使用 MNV* 的開發模式已經能夠將頁面內容渲染體驗作到接近客戶端 Native 應用的體驗了。但須要避免 js Framework 和 native Framework 的頻繁交互。