4年來的前端性能優(yōu)化常用總結(jié)

前言

不知不覺離開京東已經(jīng)快半年了?;叵肫疬@4年,很多的是感恩。


微信圖片_20190712140830.jpg

復(fù)盤了很多這些年自己學(xué)到的東西,查閱了很多的資料,對前端性能優(yōu)化做一個(gè)總結(jié)。作為一個(gè)前端開發(fā)者,性能是我們關(guān)注的指標(biāo)。它直接影響著我們的用戶,同時(shí)也影響著產(chǎn)品本身。前端發(fā)展以來,優(yōu)化方式,琳瑯滿目,這些內(nèi)容復(fù)雜繁多,往往容易被人遺忘。本篇整理了很多東西,希望對大家有幫助。

正文

前端優(yōu)化層出不窮,移動(dòng)端大行其道的現(xiàn)在,我們可以說優(yōu)化好移動(dòng)端,PC端也將會更好。所以,我們可以綜合以下圖片進(jìn)行一些分析,如圖:


041436b6f1575010917b7bb6530cf507.png

圖中已經(jīng)對前端性能做了一些概括。但其實(shí),我覺得我們可以將這個(gè)概括更加精準(zhǔn),扼要,豐富。所以,接下來我會從四個(gè)方面就前端性能進(jìn)行總結(jié):首屏優(yōu)化,網(wǎng)絡(luò)方面、DOM操作及渲染方面、數(shù)據(jù)方面。

首屏優(yōu)化

這兩天一直在看首屏優(yōu)化的文章,所以將其總結(jié)歸納一下,方便以后使用。

相對于移動(dòng)端的首屏優(yōu)化,PC在有些方面要苛刻得多,主要是因?yàn)镻C端有太多的東西想要讓用戶看到,這就難免PC端的頁面大而“重”,用戶打開速度就會相對比較慢。用戶體驗(yàn)不好。

1. 什么是首屏?

以800x600像素尺寸為標(biāo)準(zhǔn),當(dāng)瀏覽器加載頁面后看到第一眼的顯示內(nèi)容為首屏。而從開始加載到瀏覽器頁面顯示高度達(dá)到600像素且此區(qū)域有內(nèi)容顯示的時(shí)間為首屏顯示時(shí)間。

以京東首頁為例:


image.png

當(dāng)我們打開京東時(shí),第一眼看到的內(nèi)容即為首屏內(nèi)容,也就是如上圖的內(nèi)容。

2. 為什么要做首屏優(yōu)化

一個(gè)頁面的“總加載時(shí)間”要比“首屏?xí)r間”長,但對于最終用戶體驗(yàn)而言,當(dāng)內(nèi)容充滿首屏的區(qū)域時(shí),用戶就可以看到網(wǎng)站的主要內(nèi)容并可以進(jìn)行各自的選擇了。首屏?xí)r間的快與慢,直接影響到了用戶對網(wǎng)站的認(rèn)知度。
所以首屏?xí)r間的長短對于用戶的滯留時(shí)間的長短、用戶轉(zhuǎn)化率都尤為重要。

3.京東是怎么做首屏優(yōu)化的

在前端架構(gòu)上大體還是沿用過去的架構(gòu),使用 jQuery + Seajs 這種古老的開發(fā)方式,因?yàn)槭醉撨€依賴著許多舊的系統(tǒng)與組件,無法在短時(shí)間內(nèi)對基礎(chǔ)架構(gòu)進(jìn)行升級,當(dāng)然并不是說舊的就不好,要去盲目追求一些新的東西,而是這種架構(gòu)還是有可以提升的地方。為了保證首屏速度,京東首屏依然采用直出的方式,優(yōu)勢就是1:SEO優(yōu)化效果明顯,2:首屏打開速度快。缺點(diǎn)就是:服務(wù)器壓力大。于是對非首屏的樓層進(jìn)行改進(jìn),使用前端模板 + 數(shù)據(jù)開發(fā)方式,將DOM字符串的渲染放到前端來做,后端只提供數(shù)據(jù)接口,以此來達(dá)到前后端分離的效果,同時(shí)在開發(fā)中使用假數(shù)據(jù)平臺模擬接口,讓前端工作不再依賴后端。

now.jpg

雖然使用前端模板 + 數(shù)據(jù)開發(fā)方式,會使得每個(gè)樓層都多一個(gè)接口,并且需要依靠JS來動(dòng)態(tài)渲染,會影響到樓層加載的性能,但經(jīng)過測試證明在現(xiàn)代PC瀏覽器下兩種模式前端渲染和后端渲染并不會相差太多,并且在模板、數(shù)據(jù)雙重緩存下,這樣的差距更是微乎其微了,更關(guān)鍵的是能讓我們的開發(fā)效率有所提升。

compare.jpg

首屏直出是讓首屏速度更快的最佳選擇,此次版本依然選擇了首屏直出的方式,直出的內(nèi)容包括首屏HTML,頁面樓層骨架,以及樣式和一些必須的腳本,京東過去是將頁面引用的所有樣式都直出在頁面上,沒有外鏈的CSS,各種優(yōu)化手段都考慮進(jìn)去了,那么新版首頁就只能在精簡大小上下功夫了,所以新版首頁的首屏只直出了首屏必須的樣式,輪播圖也只請求了第一張的數(shù)據(jù)。同時(shí)只直出一小部分必須的腳本,而非首屏的樓層樣式拆分到各自樓層中,和樓層的模板放在一起,按需加載。

當(dāng)我們打開京東的網(wǎng)站(不要滾動(dòng)鼠標(biāo)和鍵盤),右鍵查看源代碼會發(fā)現(xiàn)京東首頁的DOM樹出奇的簡單,頁面DOM中多含有mod_lazyload的類,例如:

<div id="J_seckill" class="seckill seckill__loading mod_lazyload" aria-label="京東秒殺"></div>

再看下 localstorage,會發(fā)現(xiàn)它們的值中多存在一串完整的類似于html的內(nèi)容

dom: '{%var i,clstagPrefix = pageConfig.clstagPrefix + o.staticLogTag;var isWide = pageConfig.compatible && pageConfig.wideVersion;%}{% var len = o.list.length; len = Math.min(len, 3); %}{% if (len >= 1) { %}<div class="grid_c1 rec_inner"><ul class="rec_list">{% for(i = 0; i < len; i++){ %}{% var item = o.list[i]; %}{% var imgUrl = isWide ? item.imgUrl : item.imgUrlB; %}<li class="rec_item" fclog="{%= item.clog %}"><a href="{%= item.url %}" class="rec_lk" target="_blank" clstag="{%= clstagPrefix + \'a\' + (i < 9 ? \'0\' : \'\') + (1+i) %}"><img src="http://misc.360buyimg.com/mtd/pc/common/img/blank.png" data-lazy-img="{%= imgUrl %}" alt="{%= item.title %}" title="{%= item.title %}" class="rec_img" data-webp="no" ></a></li>{% } %}</ul></div>{% } %} ',
    style: ".rec_list{overflow:hidden;height:100px}.rec_item{overflow:hidden;float:left;width:396px;height:100%}.rec_lk{display:block;height:100%}.rec_img{display:block;margin:auto}.o2_mini .rec_item{width:330px}.csstransitions .rec_img{-webkit-transition:opacity .2s;-moz-transition:opacity .2s;transition:opacity .2s}.csstransitions .rec_lk:hover .rec_img{opacity:.8}",
    time: 1479195351434,
    version: "ff78610a0ef9cdbb"

每個(gè)樓層的dom結(jié)構(gòu)和css會緩存到localstorage中。通過版本號和時(shí)間戳來區(qū)分版本。在頁面打開的時(shí)候,會將很多公共的css,js利用對比緩存緩存到本地。其中有一個(gè)js保存所有樓層依賴的js和css的版本號,把需要請求的路徑寫在 dom 上(例如:data-tpl="elevator_tpl"),用戶滾動(dòng)時(shí),一旦該模塊進(jìn)入了視窗,則請求 dom 上對應(yīng)的 data-tpl 地址,拿到渲染這個(gè)模塊所需要的腳本和數(shù)據(jù),不過這中間還有一層本地緩存 localstorage,如果在本地緩存中匹配到了對應(yīng)的 hash string 內(nèi)容,則直接渲染,否則請求到數(shù)據(jù)之后更新本地緩存。localstorage中的 version 會在頁面加載時(shí)候,與后端文件 hash相對比,hash不變直接取localstorage中的內(nèi)容(當(dāng)然也可以使用cookie判斷版本)。

分析到這里已經(jīng)很明顯了,通過前端緩存和異步加載jd已經(jīng)完美的實(shí)現(xiàn)了首屏快速加載,在PC端達(dá)到了秒開的級別。

這里其實(shí)存在2個(gè)請求,1:樓層的初始化腳本(包含js和樣式),2:樓層需要加載的數(shù)據(jù)。

為啥不把初始化樓層的腳本和加載數(shù)據(jù)的腳本放到一個(gè)js里面?還可以減少一次請求呢。為了讓數(shù)據(jù)充分緩存下了不少功夫。數(shù)據(jù)的變化頻率比較高,如果數(shù)據(jù)和初始化腳本包裝在一起,雖然節(jié)約了一個(gè)請求,但一旦數(shù)據(jù)變化,整個(gè)腳本都得重新加載,而將數(shù)據(jù)和腳本分離,腳本可以長期緩存在本地,單獨(dú)請求數(shù)據(jù),這個(gè)量會小很多。直接改變上面的 version 版本號便可以讓瀏覽器重新請求最新腳本。

從上面可以看出,任何一個(gè)模塊的改動(dòng),在前端只會引起一個(gè)較小的加載變化,加上 http 的緩存策略,服務(wù)器的壓力也是很小的。

4.還需要注意些什么?

看了上面的內(nèi)容相信大家對于京東關(guān)于首屏優(yōu)化的方案有了一個(gè)大體的了解,下面我們再整理一下關(guān)于首屏顯示速度優(yōu)化細(xì)節(jié)上的內(nèi)容:

css靜態(tài)文件在哪里?

為了求快,首頁是沒有css外鏈的,這樣會再發(fā)起多次請求,相信對于我們來說,也是老生常談的前端優(yōu)化了。
那有人可能會問沒有css外鏈,那如果一整個(gè)頁面的css是否會增加頁面的體積?其實(shí)上面就已經(jīng)提到了,頁面切分為模塊化加載,對應(yīng)模塊下的css交給js或jsonp請求返回。整個(gè)頁面的靜態(tài)文件(圖片,腳本,css)利用對比緩存緩存到本地。

js文件怎么加載?

京東采用請求合并的方式減少了與服務(wù)器交互的時(shí)間

<script src="http://misc.360buyimg.com/??/jdf/lib/jquery-1.6.4.js,/jdf/2.0.0/ui/ui/1.0.0/ui.js,/mtd/pc/index/gb/lib.min.js,/mtd/pc/base/1.0.0/base.js,/mtd/pc/common/js/o2_ua.js,/mtd/pc/index/home/index.min.js,/mtd/pc/index/home/init.min.js"></script>

js如何執(zhí)行?

懶執(zhí)行,有交互才執(zhí)行,樓層的js進(jìn)入視口才會執(zhí)行。有興趣的可以看看小胡子哥的淘寶首頁性能優(yōu)化實(shí)踐這篇文章

圖片如何處理?

圖片在其他屏(非首屏)都采用懶加載的模式,這樣既能節(jié)省流量,也能減少請求數(shù)或延遲請求數(shù)。

首屏數(shù)據(jù)錯(cuò)誤,白屏怎么辦?
對于像京東首頁這種大流量的網(wǎng)站,后端接口可能偶爾會出現(xiàn)錯(cuò)誤,或者直接掛掉,特別是在雙11這種可能會達(dá)到流量峰值的時(shí)候,但是不能因?yàn)榻涌诔鲥e(cuò)的原因而使得頁面顯示出現(xiàn)錯(cuò)誤。這就需要前端來配合給出一套合理的災(zāi)備方案。

通常,我們通過接口緩存、超時(shí)、重試來進(jìn)行災(zāi)備處理。目前首頁大部分接口、及所有模板請求,在請求成功后都會存入本地緩存,第二次請求,假如緩存沒有過期將直接使用緩存,假如緩存過期將會重新請求,而一次正常的請求,都會經(jīng)過超時(shí)或異常重試的邏輯,來保證用戶能盡量訪問到正常的數(shù)據(jù),在正常接口無法獲取數(shù)據(jù)之后又會有兜底接口來保障數(shù)據(jù)來源,這樣的層層保障,很好地保證了頁面的完整性。而且,針對所有接口,前端均有數(shù)據(jù)校驗(yàn)邏輯,每一個(gè)后端接口都要經(jīng)過前端的數(shù)據(jù)校驗(yàn),來驗(yàn)證接口的可用性,假如接口數(shù)據(jù)異常,前端將主動(dòng)調(diào)用兜底接口來替代,這樣來保證頁面不至于錯(cuò)亂。

綜上所述,首頁的接口和模板正常請求流程如下


request_flow.jpg

網(wǎng)絡(luò)方面

web應(yīng)用,總是會有一部分的時(shí)間浪費(fèi)在網(wǎng)絡(luò)連接和資源下載方面。往往建立一次網(wǎng)絡(luò)連接是需要時(shí)間成本的。而且瀏覽器同一時(shí)間所發(fā)送的網(wǎng)絡(luò)請求數(shù)是有限的。所以,這個(gè)層面的優(yōu)化可以從「減少請求數(shù)目」開始:

  1. 減少http請求:在YUI35規(guī)則中也有提到,主要是優(yōu)化js、css和圖片資源三個(gè)方面,因?yàn)閔tml是沒有辦法避免的。因此,我們可以做一下的幾項(xiàng)操作:

    • 合并js文件

    • 合并css文件

    • 雪碧圖的使用(css sprite)

    • 使用base64表示簡單的圖片

      上述四個(gè)方法,前面兩者我們可以使用webpack之類的打包工具進(jìn)行打包;雪碧圖的話,也有專門的制作工具;圖片的編碼是使用base64的,所以,對于一些簡單的圖片,例如空白圖等,可以使用base64直接寫入html中。

回到之前網(wǎng)絡(luò)層面的問題,除了減少請求數(shù)量來加快網(wǎng)絡(luò)加載速度,往往整個(gè)資源的體積也是,平時(shí)我們會關(guān)注的方面。

  1. 減小資源體積:可以通過以下幾個(gè)方面進(jìn)行實(shí)施:

    • gzip壓縮

    • js混淆

    • css壓縮

    • 圖片壓縮

      gzip壓縮主要是針對html文件來說的,它可以將html中重復(fù)的部分進(jìn)行一個(gè)打包,多次復(fù)用的過程。js的混淆可以有簡單的壓縮(將空白字符刪除)、丑化(丑化的方法,就是將一些變量縮小)、或者可以使用php對js進(jìn)行混淆加密。css壓縮,就是進(jìn)行簡單的壓縮。圖片的壓縮,主要也是減小體積,在不影響觀感的前提下,盡量壓縮圖片,使用png等圖片格式,減少矢量圖、高清圖等的使用。這樣子的做法不僅可以加快網(wǎng)頁顯示,也能減少流量的損耗。

除了以上兩部分的操作之外,在網(wǎng)絡(luò)層面我們還需要做好緩存工作。真正的性能優(yōu)化來說,緩存是效率最高的一種,往往縮短的加載時(shí)間也是最大的。

  1. 緩存:可以通過以下幾個(gè)方面來描述:

    • DNS緩存

    • CDN部署與緩存

    • http緩存

      由于瀏覽器會在DNS解析步驟中消耗一定的時(shí)間,所以,對于一些高訪問量網(wǎng)站來說,做好DNS的緩存工作,就會一定程度上提升網(wǎng)站效率。CDN緩存,CDN作為靜態(tài)資源文件的分發(fā)網(wǎng)絡(luò),本身就已經(jīng)提升了,網(wǎng)站靜態(tài)資源的獲取速度,加快網(wǎng)站的加載速度,同時(shí)也給靜態(tài)資源做好緩存工作,有效的利用已緩存的靜態(tài)資源,加快獲取速度。http緩存,也是給資源設(shè)定緩存時(shí)間,防止在有效的緩存時(shí)間內(nèi)對資源進(jìn)行重復(fù)的下載,從而提升整體網(wǎng)頁的加載速度。

其實(shí),網(wǎng)絡(luò)層面的優(yōu)化還有很多,特別是針對于移動(dòng)端頁面來說。眾所周知,移動(dòng)端對于網(wǎng)絡(luò)的敏感度更加的高,除了目前的4G和WIFI之外,其他的移動(dòng)端網(wǎng)絡(luò)相當(dāng)于弱網(wǎng)環(huán)境,在這種環(huán)境下,資源的緩存利用是相當(dāng)重要的。而且,減少http的請求次數(shù),也是至關(guān)重要的,移動(dòng)端弱網(wǎng)環(huán)境下,對于http請求的時(shí)間也會增加。所以,我們可以看一下我們在移動(dòng)端網(wǎng)絡(luò)方面可以做的優(yōu)化:

  1. 移動(dòng)端優(yōu)化:使用以下幾種方式來加快移動(dòng)端網(wǎng)絡(luò)方面的優(yōu)化:

    • 使用長cache,減少重定向

    • 首屏優(yōu)化,保證首屏加載數(shù)據(jù)小于14kb

    • 不濫用web字體

      「使用長cache」,可以使得移動(dòng)端的部分資源設(shè)定長期緩存,這樣可以保證資源不用向服務(wù)器發(fā)送請求,來比較資源是否更新,從而避免304的情況。304重定向,在PC端或許并不會影響網(wǎng)頁的加載速度,但是,在移動(dòng)端網(wǎng)絡(luò)不穩(wěn)定的前提下,多一次請求,就多了一部分加載時(shí)間?!甘灼羶?yōu)化」,對于移動(dòng)端來說是至關(guān)重要的。2s時(shí)間是用戶的最佳體驗(yàn),一旦超出這個(gè)時(shí)間,將會導(dǎo)致用戶的流失。所以,針對移動(dòng)端的網(wǎng)絡(luò)情況,不可能在這么短時(shí)間內(nèi)加載完成所有的網(wǎng)頁資源,所以我們必須保證首屏中的內(nèi)容被優(yōu)先顯示出來,而且基于TCP的慢啟動(dòng)和擁塞控制,第一個(gè)14kb的數(shù)據(jù)是非常重要的,所以需要保證首部加載數(shù)據(jù)能夠小于14kb?!覆粸E用web字體」,web字體的好處就是,可以代替某些圖片資源,但是,在移動(dòng)端過多的web字體的使用,會導(dǎo)致頁面資源加載的繁重,所以,慎用web字體

渲染和DOM操作方面

首先,簡單的聊一下優(yōu)化渲染的重要性。在網(wǎng)頁初步加載時(shí),獲取到HTML文件之后,最初的工作是構(gòu)建DOM和構(gòu)建CSSOM兩個(gè)樹,之后將他們合并形成渲染樹,最后對其進(jìn)行打印。我們可以通過圖片來看一下,簡單的過程:


65cb9084be1f3bc63562783920428926.png

這里整個(gè)過程拉出來寫,具體可以再寫一篇文章,恕我偷下懶,推薦一篇比較好的文章給大家吧。瀏覽器渲染過程與性能優(yōu)化

繼續(xù)我們的話題,我們可以如何去縮短這個(gè)過程呢?可以從以下幾個(gè)操作進(jìn)行優(yōu)化。

  1. 優(yōu)化網(wǎng)頁渲染

    • css的文件放在頭部,js文件放在尾部或者異步

    • 盡量避免內(nèi)聯(lián)樣式

      css文件放在「頭部加載」,可以保證解析DOM的同時(shí),解析css文件。因?yàn)?,CSS(外鏈或內(nèi)聯(lián))會阻塞整個(gè)DOM的渲染,然而DOM解析會正常進(jìn)行,所以將css文件放在頭部進(jìn)行解析,可以加快網(wǎng)頁的構(gòu)建速度。假設(shè)將其放在尾部,那時(shí)DOM樹幾乎構(gòu)建,這時(shí)就得等到CSSOM樹構(gòu)建完成,才能夠繼續(xù)下面的步驟。「js放在尾部」:js文件不同,將js文件放在尾部或者異步加載的原因是JS(外鏈或內(nèi)聯(lián))會阻塞后續(xù)DOM的解析,后續(xù)DOM的渲染也將被阻塞,而且一旦js中遇到DOM元素的操作,很可能會影響。這方面可以推薦一篇文章——異步腳本載入提高頁面性能?!副苊馐褂脙?nèi)聯(lián)樣式」,可以有效的減少html的體積,一般考慮內(nèi)聯(lián)樣式的時(shí)候,往往是樣式本身體積比較小,往往加載網(wǎng)絡(luò)資源的時(shí)間會大于它的時(shí)候。

除了頁面渲染層面的優(yōu)化,當(dāng)然最重要的就是DOM操作方面的優(yōu)化,這部分的優(yōu)化應(yīng)該是最多的,而且也是平時(shí)開發(fā)可以注意的地方。如果開發(fā)前期明白這些原理,同時(shí)付諸實(shí)踐的話,就可以在后期的性能完善上面少下很多功夫。那么,接下來我們可以來看一下具體的操作:

  1. DOM操作優(yōu)化

    • 避免在document上直接進(jìn)行頻繁的DOM操作

    • 對于加了動(dòng)畫的UI元素,設(shè)置position為absolute或fixed

    • 如果需要?jiǎng)?chuàng)建多個(gè)DOM節(jié)點(diǎn),可以使用DocumentFragment創(chuàng)建完后一次性的加入document;

    • 合并多次的DOM和樣式的修改。并減少對style樣式的請求

    • 盡量使用css動(dòng)畫

    • 使用事件代理

      前面四個(gè)操作,其實(shí)都是希望『減少重排和重繪』。其實(shí),進(jìn)行一次DOM操作的代價(jià)是非常之大的,以前可以通過網(wǎng)頁操作是否卡頓來進(jìn)行判斷,但是,現(xiàn)代瀏覽器的進(jìn)步已經(jīng)大大減少了這方面的影響。但是,我們還是需要清楚,如何去減少回流和重繪的問題。因?yàn)檫@里不想細(xì)說這方面的知識,想要了解的話,可以看這篇文章——回流與重繪:CSS性能讓JavaScript變慢?。這可是張鑫旭大大的一篇文章呦(.)?!副M量使用css動(dòng)畫」,是因?yàn)楸旧韈ss動(dòng)畫比較簡單,而且相較于js的復(fù)雜動(dòng)畫,瀏覽器本身對其進(jìn)行了優(yōu)化,使用上面不會出現(xiàn)卡頓等問題?!甘褂胷equestAnimationFrame代替setInterval操作」,相信大家都有所耳聞,setInterval定時(shí)器會有一定的延時(shí),對于變動(dòng)性高的動(dòng)畫來說,會出現(xiàn)卡頓現(xiàn)象。而requestAnimationFrame正好解決的整個(gè)問題?!高m當(dāng)使用canvas」,不得不說canvas是前端的一個(gè)進(jìn)步,出現(xiàn)了它之后,前端界面的復(fù)雜性也隨之提升了。一些難以完成的動(dòng)畫,都可以使用canvas進(jìn)行輔助完成。但是,canvas使用頻繁的話,會加重瀏覽器渲染的壓力,同時(shí)導(dǎo)致性能的下降。所以,適當(dāng)時(shí)候使用canvas是一個(gè)不錯(cuò)的建議?!副M量減少css表達(dá)式的使用」,這個(gè)在YUI規(guī)則中也被提到過,往往css的表達(dá)式在設(shè)計(jì)之初都是美好的,但在使用過程中,由于其頻繁觸發(fā)的特性,會拖累網(wǎng)頁的性能,出現(xiàn)卡頓。因此在使用過程中盡量減少css表達(dá)式的使用,可以改換成js進(jìn)行操作。「使用事件代理」:往往對于具備冒泡性質(zhì)的事件來說,使用事件代理不失為一種好的方法。舉個(gè)例子:一段列表都需要設(shè)定點(diǎn)擊事件,這時(shí)如果你給列表中的每一項(xiàng)設(shè)定監(jiān)聽,往往會導(dǎo)致整體的性能下降,但是如果你給整個(gè)列表設(shè)置一個(gè)事件,然后通過點(diǎn)擊定位目標(biāo)來觸發(fā)相應(yīng)的操作,往往性能就會得到改善。

DOM操作的優(yōu)化,還有很多,當(dāng)然也包括移動(dòng)端的。這個(gè)會在之后移動(dòng)端優(yōu)化部分被提及,此處先賣個(gè)關(guān)子。上面我們概述了開始渲染的時(shí)候和DOM操作的時(shí)候的一些注意事項(xiàng)。接下來要講的是一些小細(xì)節(jié)的注意,這些細(xì)節(jié)可能對于頁面影響不大,但是一旦堆積多了,性能也會有所影響。

  1. 操作細(xì)節(jié)注意

    • 正確使用icon-font

    • 在css屬性為0時(shí),去掉單位

    • 禁止圖像縮放

    • 正確的css前綴的使用

    • 移除空的css規(guī)則

    • 對于css中可繼承的屬性,如font-size,盡量使用繼承,少一點(diǎn)設(shè)置

    • 縮短css選擇器,多使用偽元素等幫助定位

      上述的一些操作細(xì)節(jié),是平時(shí)在開發(fā)中被要求的,更可以理解為開發(fā)規(guī)范。(基本操作,坐下_)

列舉完基本操作之后,我們再來聊一下移動(dòng)端在DOM操作方面的一些優(yōu)化。

  1. 移動(dòng)端優(yōu)化

    • 長列表滾動(dòng)優(yōu)化

    • 函數(shù)防抖和函數(shù)節(jié)流

    • 使用touchstart、touchend代替click

    • HTML的viewport設(shè)置

    • 開啟GPU渲染加速

      首先,長列表滾動(dòng)問題,是移動(dòng)端需要面對的,IOS盡量使用局部滾動(dòng),android盡量使用全局滾動(dòng)。同時(shí),需要給body添加上-webkit-overflow-scrolling: touch來優(yōu)化移動(dòng)段的滾動(dòng)。如果有興趣的同學(xué),可以去了解一下ios和android滾動(dòng)操作上的區(qū)別以及優(yōu)化。「防抖和節(jié)流」,設(shè)計(jì)到滾動(dòng)等會被頻繁觸發(fā)的DOM事件,需要做好防抖和節(jié)流的工作。它們都是為了限制函數(shù)的執(zhí)行頻次,以優(yōu)化函數(shù)觸發(fā)頻率過高導(dǎo)致的響應(yīng)速度跟不上觸發(fā)頻率,出現(xiàn)延遲,假死或卡頓的現(xiàn)象。

      介紹:函數(shù)防抖,當(dāng)調(diào)用動(dòng)作過n毫秒后,才會執(zhí)行該動(dòng)作,若在這n毫秒內(nèi)又調(diào)用此動(dòng)作則將重新計(jì)算執(zhí)行時(shí)間;函數(shù)節(jié)流,預(yù)先設(shè)定一個(gè)執(zhí)行周期,當(dāng)調(diào)用動(dòng)作的時(shí)刻大于等于執(zhí)行周期則執(zhí)行該動(dòng)作,然后進(jìn)入下一個(gè)新周期。

      「touchstart、touchend代替click」,也是移動(dòng)端比較常用的操作。click在移動(dòng)端會有300ms延時(shí),這應(yīng)該是一個(gè)常識唄。(不知道的小伙伴該收藏一下呦)。這種方法會影響用戶的體驗(yàn)。所以做優(yōu)化時(shí),最簡單的方法就是使用touchstart或者touchend代替click。因?yàn)樗鼈兪录?zhí)行順序是touchstart->touchmove->touchend->click。或者,使用fastclick或者zepto的tap事件代替click事件?!窰TML的viewport設(shè)置」,可以防止頁面的縮放,來優(yōu)化性能?!搁_啟GPU渲染加速」,小伙伴們一定聽過CPU吧,但是這里的GPU不能和CPU混為一談呦。GPU的全名是Graphics Processing Unit,是一種硬件加速方式。一般的css渲染,瀏覽器的渲染引擎都不會使用到它。但是,在3D渲染時(shí),計(jì)算量較大,繁重,瀏覽器會開啟顯卡的硬件加速來幫助完成這些操作。所以,我們這里可以使用css中的translateZ設(shè)定,來欺騙瀏覽器,讓其幫忙開啟GPU加速,加快渲染進(jìn)程。

DOM部分的優(yōu)化,更多的是習(xí)慣。需要自己強(qiáng)制要求自己在開發(fā)過程中去注意這些規(guī)范。所以,這部分的內(nèi)容可以多關(guān)注一下,才能夠慢慢了解。同時(shí),本人對于上述幾點(diǎn)的描述是概括性的。并沒有對其進(jìn)行詳細(xì)的展開。因此,也要求你去細(xì)細(xì)的查閱Google呦。

數(shù)據(jù)方面

數(shù)據(jù),也可以說是前端優(yōu)化方面比較重要的一塊內(nèi)容。頁面與用戶的交互響應(yīng),往往伴隨著數(shù)據(jù)交互,處理,以及ajax的異步請求等內(nèi)容。所以,我們也可以來聊聊這一塊的知識。首先是對于圖片數(shù)據(jù)的處理:

  1. 圖片加載處理

    • 圖片預(yù)加載

    • 圖片懶加載

    • 首屏加載時(shí)進(jìn)度條的顯示

      「圖片預(yù)加載」,預(yù)加載的寓意就是提前加載內(nèi)容。而圖片的預(yù)加載往往會被用在圖片資源比較大,即時(shí)加載時(shí)會導(dǎo)致很長的等待過程時(shí),才會被使用的。常見場景:圖片漫畫展示時(shí)。往往會預(yù)加載一張到兩張的圖片?!笀D片懶加載」,懶加載或許你是第一次聽說,但是,這種方式在開發(fā)中會被經(jīng)常使用。首先,我們需要明白一個(gè)道理:往往只有看到的資源是必須的,其他資源是可以隨著用戶的滾動(dòng),隨即顯示的。所以,特別是對于圖片資源特別多的網(wǎng)站來說,做好圖片的懶加載是可以大大提升網(wǎng)頁的載入速度的。

      常見的圖片懶加載的方式就是:在最初給圖片的src設(shè)置一個(gè)比較簡單的圖片,然后將圖片的真實(shí)地址設(shè)置給自定義的屬性,做一個(gè)占位,然后給圖片設(shè)置監(jiān)聽事件,一旦圖片到達(dá)視口范圍,從圖片的自定義屬性中獲取出真是地址,然后賦值給src,讓其進(jìn)行加載。

      「首屏進(jìn)度條的顯示」:往往對于首屏優(yōu)化后的數(shù)據(jù)量并不滿意的話,同時(shí)也不能進(jìn)一步縮短首屏包的長度了,就可以使用進(jìn)度條的方式,來提醒用戶進(jìn)行等待。

講完了圖片這一塊數(shù)據(jù)資源的處理,往往我們需要去優(yōu)化一下異步請求這一部分的內(nèi)容。因?yàn)椋惒降臄?shù)據(jù)獲取也是前端不可分割的。這一部分我們也可以做一定的處理:

  1. 異步請求的優(yōu)化

    • 使用正常的json數(shù)據(jù)格式進(jìn)行交互

    • 部分常用數(shù)據(jù)的緩存

    • 數(shù)據(jù)埋點(diǎn)和統(tǒng)計(jì)

      「JSON交互」,JSON的數(shù)據(jù)格式輕巧,結(jié)構(gòu)簡單,往往可以大大優(yōu)化前后端的數(shù)據(jù)通信?!赋S脭?shù)據(jù)的緩存」,可以將一些用戶的基本信息等常用的信息做一個(gè)緩存,這樣可以保證ajax請求的減少。同時(shí),HTML5新增的storage的內(nèi)容,也不用怕cookie暴露,引起的信息泄漏問題?!笖?shù)據(jù)埋點(diǎn)和統(tǒng)計(jì)」,對于資深的程序員來說,比較了解。而且目前的大部分公司也會做這方面的處理。有心的小伙伴可以自行查閱。

最后,還有就是大量數(shù)據(jù)的運(yùn)算。對于javascript語言來說,本身的單線程就限制了它并不能計(jì)算大量的數(shù)據(jù),往往會造成頁面的卡頓。而可能業(yè)務(wù)中有些復(fù)雜的UI需要去運(yùn)行大量的運(yùn)算,所以,webWorker的使用是至關(guān)重要的?;蛟S,前端標(biāo)準(zhǔn)普及的落后,會導(dǎo)致大家對于這些新生事物的短暫缺失吧。

總結(jié)

本篇文章就前端性能這個(gè)話題做了一個(gè)總結(jié)?;蛟S,并不全面,但是都是一些平時(shí)開發(fā)中會被經(jīng)常用到的知識。希望有心者能夠去親身的嘗試一下這些方面的優(yōu)化。本篇的概述了一下幾個(gè)知識點(diǎn):

  • 首屏優(yōu)化
  • 網(wǎng)絡(luò)層面的優(yōu)化
  • 數(shù)據(jù)層面的優(yōu)化
  • DOM操作與渲染層面的優(yōu)化

另外,寫代碼的時(shí)候注意代碼規(guī)范。
京東UED代碼規(guī)范

參考:
https://juejin.im/post/59e1bbc9f265da430f311fb1

https://juejin.im/post/59d489156fb9a00a571d6509

https://www.cnblogs.com/jingh/p/6531105.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容