網(wǎng)絡(luò)加載類
首屏數(shù)據(jù)請求提前,避免JavaScript文件加載后才請求渲染
為了進(jìn)一步提示頁面加載速度,可以考慮將頁面的數(shù)據(jù)請求盡可能提前,避免在JavaScript文件加載完成后才去請求數(shù)據(jù)。通常數(shù)據(jù)請求是頁面內(nèi)容渲染中關(guān)鍵路徑最長的部分,而且不能并行,所以如果數(shù)據(jù)請求能提前的話,可以極大程度上縮短頁面內(nèi)容的渲染完成時間。首屏加載和按需加載,非首屏內(nèi)容滾屏加載,保證首屏內(nèi)容最小化
由于移動端網(wǎng)絡(luò)相對較慢,網(wǎng)絡(luò)資源有限,因此為了保證盡快完成頁面內(nèi)容的加載,需要保證首屏加載資源的最小化,非首屏的內(nèi)容使用滾動的方式異步加載。一般推薦移動端頁面首屏數(shù)據(jù)展示延遲不超過3秒。模塊化資源并行下載
主要指模塊化JavaScript資源的異步加載,例如AMD的異步模塊,使用并行的加載方式能夠縮短多個文件資源的加載時間。inline首屏必備的CSS和JavaScript
通常為了在HTML加載完成時能使瀏覽器中有基本的樣式,需要將頁面渲染時必備的CSS和JS通過script或style的方式內(nèi)聯(lián)到頁面中,避免頁面HTML載入完成到頁面內(nèi)容展示這段過程中頁面出現(xiàn)空白meta dns prefetch設(shè)置DNS預(yù)解析
設(shè)置文件資源的DNS預(yù)解析,能讓瀏覽器提前解析獲取靜態(tài)資源的主機(jī)IP,避免等到請求的時候才發(fā)起DNS解析。
<meta http-equiv='x-dns-prefetch-control' content='on'><link rel="dns-prefetch" >資源預(yù)加載
首屏加載完成后可能會使用的資源,我們可以用 link標(biāo)簽聲明特定文件的預(yù)加載
<link rel='subresource' href='main.css'><link rel='prefetch' href='secondary.js'>
注意:只有可緩存的資源才進(jìn)行預(yù)加載,否則浪費(fèi)資源!
Pre render預(yù)渲染
預(yù)渲染意味著我們提前加載好用戶即將訪問的下一個頁面,否則進(jìn)行預(yù)渲染這個頁面將浪費(fèi)資源,慎用!
<link rel='prerender' href='//j.autohome.com.cn'>合理利用MTU策略
通常情況下,TCP網(wǎng)絡(luò)傳輸?shù)淖畲髠鬏攩卧∕TU)為1500B,即一個RTT(Round-Trip Time,網(wǎng)絡(luò)請求返回時間)內(nèi)可以傳輸?shù)臄?shù)據(jù)量最大為1500字節(jié)(為什么以太網(wǎng)mtu值被設(shè)定為1500 - 知乎)。因此在前后端分離的開發(fā)模式中,盡量保證頁面的HTML內(nèi)容在1KB以內(nèi),這樣整個HTML內(nèi)容的請求就可以在一個RTT內(nèi)完成,最大限度的提高了HTML載入速度
緩存
- 合理利用瀏覽器緩存
除了上一節(jié)說到的Cache-Control、Expires、Etag和Last-Modified來設(shè)置HTTP緩存外,在移動端還可以使用localstorage等來保存ajax返回的數(shù)據(jù),或者使用localstorage保存CSS或JS等靜態(tài)資源,實(shí)現(xiàn)移動端的離線應(yīng)用,盡可能的減少網(wǎng)絡(luò)請求,保證靜態(tài)資源內(nèi)容的快速加載。 - 靜態(tài)資源離線方案
對于移動端或者混合應(yīng)用,可以設(shè)置離線文件或離線包機(jī)制讓靜態(tài)資源請求從本地讀取,加快資源載入速度,并實(shí)現(xiàn)離線更新。這塊推薦葉小釵大神的前端優(yōu)化帶來的思考,淺談前端工程化 可以挑著看。離線資源這塊東西太多了,以后有時間單獨(dú)拿出來寫 - 嘗試使用 AMP HTML
AMP HTML 可以作為優(yōu)化前端頁面性能的一個解決方案,使用AMP Component中的元素來代替原始頁面元素進(jìn)行直接渲染 [譯]關(guān)于谷歌的AMP,你需要知道這些。
圖片類
圖片壓縮處理
移動端通常要保證頁面中一切用到的圖片都是經(jīng)過壓縮優(yōu)化處理,而不是以原圖的形式直接使用的,因?yàn)槟菢雍芟牧髁浚⑶壹虞d時間更長。使用較小的圖片,合理使用base64內(nèi)嵌圖片
在頁面使用的背景圖片不多且比較小的情況下,可以把圖片轉(zhuǎn)成base64編碼嵌入到html頁面或者CSS文件中,這樣可以減少頁面的HTTP請求數(shù)。需要注意的是,要保證圖片較小,一般超過5kb的就不推薦base64嵌入顯示了(前端開發(fā)中,使用base64圖片的弊端是什么? - 知乎)-
使用更高壓縮比格式的圖片
使用具有較高壓縮比格式的圖片,如webp等。在同等圖片畫質(zhì)的情況下,高壓縮比格式的圖片體積更小,能夠更快的完成文件傳輸,節(jié)省網(wǎng)站流量。
圖片懶加載
為了保證頁面內(nèi)容最小化,加速頁面渲染,盡可能節(jié)省首屏網(wǎng)絡(luò)流量,頁面中的圖片資源推薦使用懶加載實(shí)現(xiàn),在頁面滾動時動態(tài)載入圖片。使用Media Query 或者 srcset 根據(jù)不同屏幕加載不同大小的圖片
針對不同屏幕尺寸和分辨率,輸出不同大小的圖片或者背景圖能保證用戶體驗(yàn)不降低的前提下節(jié)省網(wǎng)絡(luò)流量,加快部分機(jī)型圖片載入速度,這在移動端非常值得推薦使用iconfont代替圖片圖標(biāo)
iconfont體積較小而且是矢量圖,因此縮放不會失真,還可以方便修改圖片大小和呈現(xiàn)的顏色,但是需要注意iconfont引用不同webfont格式會有兼容問題。定義圖片大小限制
加載單張圖片不建議超過30KB,避免大圖片加載時間過長而阻塞頁面其他資源的下載。如果用戶上傳的圖片過大,建議設(shè)置限制。
腳本類
- 盡量使用id選擇器
選擇頁面DOM元素時盡量使用id選擇器,因?yàn)閕d選擇器速度最快 - 合理的緩存dom對象
對于需要重復(fù)使用的dom對象,要優(yōu)先設(shè)置緩存變量,避免每次使用時都要從整個dom樹重新查找。
// 不推薦$("#mod .active").removeClass('active');$("#mod .not-active").addClass("active");// 推薦const $mod = $("#mod");$mod.find(".active").removeClass("active")$mod.find(".not-active").addClass("active")
jq 上有很多優(yōu)化建議,詳情搜索JQ 優(yōu)化
頁面元素盡量使用事件代理,避免事件直接綁定
使用事件代理可以避免對每個元素都進(jìn)行綁定。并且可以避免出現(xiàn)內(nèi)存泄漏以及需要動態(tài)添加元素的事件綁定問題
// 不推薦$(".btn").click( _ => console.log("hello") )// 推薦$(document).on("click", ".btn", _ => console.log("world"))使用touch代理click
由于移動端屏幕的設(shè)計(jì),touch事件和click事件觸發(fā)之間存在300ms延遲,所以在頁面沒有touchmove實(shí)現(xiàn)滾動處理的情況,可以用touchstart代替元素的click事件,加快頁面點(diǎn)擊的響應(yīng)速度,提高用戶體驗(yàn)。但同時也需要注意頁面重疊元素touch動作的點(diǎn)透問題。
// 不推薦$("body").on("click",".btn",function(){ console.log(this) });// 推薦$("body").on("tap",".btn",function(){ console.log(this) });// tap為zepto用touch事件封裝的避免touchmove,scroll等連續(xù)事件處理
需要對這類高頻觸發(fā)回調(diào)的事件設(shè)置函數(shù)節(jié)流(throttle | debounce),避免頻繁的事件調(diào)用導(dǎo)致移動端頁面卡頓避免使用eval、with,使用join代替連接符+,推薦使用ES6的模板字符串
基本的安全腳本編寫問題,盡可能使用高效率的特性來完成這些操作,避免不規(guī)范或者不安全的寫法。盡量使用ES6+的特性來編程
ES6+在一定程度上更高效,在chrome59版本對ES6做了深度優(yōu)化之后,很多特性速度提升了80%左右,這也是未來規(guī)范的需要。ES8前段時間也已經(jīng)落地了,如果你還沒有掌握ES6語法的話,抓緊時間學(xué)吧...
渲染類
使用viewport固定屏幕渲染,可以加速頁面渲染內(nèi)容
一般認(rèn)為,在移動端設(shè)置viewport可以加速頁面的渲染,同時可以避免縮放導(dǎo)致頁面重排重繪。
// 利用meta標(biāo)簽對viewport進(jìn)行控制<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">避免各種形式重排(reflow)重繪(redraw)
頁面的重排重繪很耗性能,所以一定要盡可能減少頁面的重排重繪,例如頁面圖片大小變化、元素位置變化這些情況都會導(dǎo)致重排與重繪使用CSS3動畫,開啟GPU加速
使用CSS3動畫可以設(shè)置transform: translateZ(0)來開啟移動設(shè)備瀏覽器的GPU圖形處理加速。這里安利一波京東凹凸實(shí)驗(yàn)室,講的挺好的,GPU加速是什么合理使用canvas和requestAnimationFrame
選擇canvas或者requestAnimationFrame等更高效的動畫實(shí)現(xiàn)方式,避免使用settimeout、setInterval等方式直接處理連續(xù)動畫SVG代替圖片
部分情況下可以考慮使用SVG代替圖片實(shí)現(xiàn)動畫,因?yàn)镾VG格式內(nèi)容更小,而且SVG的DOM結(jié)構(gòu)方便調(diào)整不濫用float
在DOM渲染樹生成后的布局渲染階段,使用float的元素布局計(jì)算比較耗性能,所以盡量減少float的使用,推薦使用固定布局或者flex布局的方式來實(shí)現(xiàn)頁面的元素布局不濫用web字體或過多的font-size聲明
過多的font-size聲明會增加字體的計(jì)算大小,而且也沒啥必要
架構(gòu)協(xié)議
- 嘗試使用SPDY和HTTP2
在條件允許的情況下可以考慮使用SPDY協(xié)議來進(jìn)行文件資源傳輸,利用連接復(fù)用加快傳輸過程,縮短資源加載時間。HTTP2在未來也一定會成為主流的 - 使用后端數(shù)據(jù)渲染
SSR( Server Side Rendering,服務(wù)端渲染)的方式可以加速頁面內(nèi)容的渲染展示,避免空白頁面的出現(xiàn),同時可以解決頁面SEO的問題。條件允許的話,SSR是一個很好的實(shí)踐思路。百度SSP單頁式應(yīng)用性能優(yōu)化實(shí)踐,React 同構(gòu)實(shí)踐與思考 - 使用Native View代替DOM的性能劣勢
可以嘗試使用Native View的MNV* 開發(fā)模式來避免HTML DOM性能慢的問題,目前使用MNV* 的開發(fā)模式已經(jīng)可以將頁面內(nèi)容渲染體驗(yàn)做到接近客戶端Native應(yīng)用的體驗(yàn)了。
關(guān)于頁面優(yōu)化的常用技術(shù)手段和思路主要包括以上這些,有部分遺漏歡迎補(bǔ)充。大家可以根據(jù)需要將這些方法應(yīng)用到自己的項(xiàng)目中去,想全部做到幾乎是不可能的,但做到用戶可以接受的程度還是很容易的。
軟件工程沒有銀彈,在我們做到了極致優(yōu)化的同時也需要付出很大的代價,這也是前端優(yōu)化的一個問題。理論上這些優(yōu)化都可以實(shí)現(xiàn),但是我們也要懂得權(quán)衡,優(yōu)化提升了用戶體驗(yàn),使數(shù)據(jù)加載更快,但是項(xiàng)目代碼卻可能打亂,異步內(nèi)容要拆分出來,首屏雪碧圖可能要拆分2個或更多,項(xiàng)目代碼維護(hù)成本成倍增加,項(xiàng)目結(jié)構(gòu)也可能變得混亂。任何一部分優(yōu)化都可以做得很深入,但不一定都值得。在優(yōu)化的同時考慮性價比,這才是我們作為一名前端工程師處理前端優(yōu)化時該具有的正確思維。