一,性能問(wèn)題的簡(jiǎn)單分析、直接表現(xiàn)、根本原因
簡(jiǎn)單分析:
???首先,一個(gè)完整的頁(yè)面主要由兩部分組成,一是UI,二是數(shù)據(jù)。如果按照MVC架構(gòu),或是數(shù)據(jù)與表現(xiàn)分離的思想,還可以細(xì)分成三部分。一是通過(guò)html(結(jié)構(gòu))+css(表現(xiàn))渲染出來(lái)的UI層(view),二是通過(guò)http來(lái)完成的數(shù)據(jù)層(model),三是將數(shù)據(jù)填充到view或者DOM操作的控制層(controller)。
???于是,一次完整的頁(yè)面加載就可以分成三部分工作,一是view渲染(UI),二是數(shù)據(jù)加載(http),三是數(shù)據(jù)填充到view或更改(DOM操作)。其中只要有一個(gè)環(huán)節(jié)出問(wèn)題,都有可能造成性能問(wèn)題。
綜上所述,我們可以總結(jié)出三個(gè)主要可能造成性能問(wèn)題的環(huán)節(jié):UI渲染、http請(qǐng)求、DOM操作。
???總而言之,要優(yōu)化性能問(wèn)題,就需要對(duì)可能造成性能問(wèn)題的環(huán)節(jié)逐個(gè)擊破。
直接表現(xiàn):
1,頁(yè)面加載時(shí)間過(guò)長(zhǎng)
2,卡頓、閃現(xiàn)、頁(yè)面結(jié)構(gòu)錯(cuò)亂等現(xiàn)象
根本原因:
1,DOM結(jié)構(gòu)復(fù)雜
2,過(guò)度或不恰當(dāng)?shù)腄OM操作
3,http請(qǐng)求過(guò)多、請(qǐng)求時(shí)間過(guò)長(zhǎng)、請(qǐng)求異常(中斷、無(wú)響應(yīng)、請(qǐng)求錯(cuò)誤)等情況
下面,針對(duì)以上可能造成性能問(wèn)題的環(huán)節(jié),進(jìn)行逐個(gè)優(yōu)化。
二,性能優(yōu)化之——DOM結(jié)構(gòu)優(yōu)化
1,保證簡(jiǎn)潔、清晰的html結(jié)構(gòu),減少或避免多余的html標(biāo)簽
2,使用HTML5的web語(yǔ)義化標(biāo)簽,保證結(jié)構(gòu)清晰,同時(shí)利于seo
3,避免過(guò)于復(fù)雜的DOM結(jié)構(gòu),避免過(guò)度嵌套
4,采用SPA(單頁(yè)應(yīng)用)模式開(kāi)發(fā),動(dòng)態(tài)按需加載
三,性能優(yōu)化之——DOM操作優(yōu)化
1,理解DOM操作:
為什么DOM操作會(huì)引起性能問(wèn)題?
首先,每次DOM操作,頁(yè)面DOM結(jié)構(gòu)通常都有可能會(huì)被改變,瀏覽器一旦檢測(cè)到DOM結(jié)構(gòu)發(fā)生改變,就會(huì)進(jìn)行全局的重繪,相當(dāng)于每次DOM操作都對(duì)頁(yè)面重新渲染了一遍。
因此DOM操作的過(guò)程其實(shí)是頁(yè)面不斷重復(fù)渲染的過(guò)程,如果這個(gè)過(guò)程很復(fù)雜,或者操作頻繁,或邏輯錯(cuò)誤,就會(huì)造成性能問(wèn)題。
可是,DOM操作是不可避免的,于是我們優(yōu)化的思路是減少DOM操作頻率。
2, 減少DOM操作的方法:
(1) 使用innerHTML屬性替代DOM操作
innerHTML不會(huì)進(jìn)行全局的重繪,而是局部重繪,因此對(duì)性能影響較小。
(2) 使用react、vue等性能較好的框架
這類(lèi)框架都對(duì)DOM操作進(jìn)行過(guò)特殊處理,性能較好。以react為例,react內(nèi)部將虛擬DOM、diff算法、
innerHTML三者結(jié)合起來(lái)處理DOM操作,避免了用戶直接操作DOM。
(3) 避免或減少使用jquery等DOM操作庫(kù)
四,性能優(yōu)化之——http優(yōu)化
http性能優(yōu)化方法:優(yōu)化靜態(tài)資源和api請(qǐng)求。
(一) 理解http請(qǐng)求
1,理解http請(qǐng)求的類(lèi)型
http請(qǐng)求分兩大類(lèi),一類(lèi)是靜態(tài)資源請(qǐng)求,另一類(lèi)就是api請(qǐng)求(請(qǐng)求后臺(tái)接口)。
** (1) 靜態(tài)資源請(qǐng)求 **
所謂靜態(tài)資源請(qǐng)求,就是頁(yè)面加載時(shí)從服務(wù)器下載html、css、js、圖片等靜態(tài)資源文件。
靜態(tài)資源請(qǐng)求,如下圖:

** (2) api請(qǐng)求 **
所謂api請(qǐng)求,就是請(qǐng)求后臺(tái)的接口所發(fā)出的http請(qǐng)求。如下圖:

簡(jiǎn)而言之,http性能優(yōu)化,其實(shí)是對(duì)靜態(tài)資源(html、css、js、圖片)和api請(qǐng)求的優(yōu)化。
2,理解http請(qǐng)求帶來(lái)的性能問(wèn)題:
如果你理解http工作原理,那應(yīng)該知道每次http請(qǐng)求過(guò)程的復(fù)雜性,代價(jià)是很高的。
因此,如果出現(xiàn)http請(qǐng)求過(guò)多、請(qǐng)求時(shí)間過(guò)長(zhǎng)、請(qǐng)求異常(中斷、無(wú)響應(yīng)、請(qǐng)求錯(cuò)誤)等都有可能會(huì)對(duì)性能造成影響。
下面就針對(duì)http請(qǐng)求的優(yōu)化方案展開(kāi)講解。
(二) 靜態(tài)資源優(yōu)化
靜態(tài)資源有html、css、js、圖片等類(lèi)型。因此要對(duì)它們進(jìn)行分門(mén)別類(lèi)地優(yōu)化。
如果請(qǐng)求的靜態(tài)資源過(guò)多、過(guò)大、或不存在等,都可能會(huì)造成性能問(wèn)題。
靜態(tài)資源優(yōu)化的辦法,就是對(duì)靜態(tài)資源進(jìn)行切割、合并、壓縮等處理,以達(dá)到縮小靜態(tài)資源體積、減少靜態(tài)資源請(qǐng)求次數(shù)等目標(biāo),以實(shí)現(xiàn)快速完成http請(qǐng)求的過(guò)程。
下面對(duì)靜態(tài)資源優(yōu)化,分門(mén)別類(lèi)來(lái)講解。
1,html結(jié)構(gòu)優(yōu)化
(1) 保證簡(jiǎn)潔、清晰的html結(jié)構(gòu),減少或避免多余的html標(biāo)簽
(2) 使用HTML5的web語(yǔ)義化標(biāo)簽,結(jié)構(gòu)清晰且利于seo
(3) css文件在head中引入,js文件放在body底部引入,這樣做可以防止阻塞。另外如果有需要提前加
載的js,請(qǐng)?jiān)趙indow.onload方法中處理。
解釋?zhuān)?瀏覽器加載js文件時(shí)其他一切渲染活動(dòng)都會(huì)停止,直到j(luò)s文件下載完成, 如果把js文件放頭部
加載,就會(huì)造成阻塞,也就是加載js時(shí)會(huì)阻止頁(yè)面渲染。 因此通常js文件需要放body底部加
載,等頁(yè)面渲染完成后再加載js文件。
2,css優(yōu)化
(1) 使用gulp、webpack等構(gòu)建工具,對(duì)css進(jìn)行合并、壓縮等處理,以縮小css文件體積
(2) 如果你的應(yīng)用css樣式很龐大,可拆分成多個(gè)css文件,并做壓縮處理,避免單個(gè)css文件過(guò)大
(3) 如果使用webpack,推薦使用extract-text-webpack-plugin之類(lèi)的插件將css樣式抽離出來(lái),防止其隨js一起打包
(4) 如果使用react、vue等框架,推薦使用css-modules、css in js等css模塊化解決方案。
(5) 使用sass/less等預(yù)編譯處理方案(后期不推薦使用,推薦使用css模塊化方案)
(6) 盡量減少或避免使用內(nèi)聯(lián)樣式
(7) 對(duì)于一些需要復(fù)雜計(jì)算的樣式,比如box-shadow、import等,減少使用。
(8) 使用css3動(dòng)畫(huà)時(shí),請(qǐng)開(kāi)啟GPU硬件加速。
3,js優(yōu)化
(1) 使用gulp、webpack等構(gòu)建工具進(jìn)行合并、壓縮處理,以縮小js文件體積和數(shù)量
(2) 使用webpack構(gòu)建時(shí),推薦拆分成2-3個(gè)js文件進(jìn)行打包,并開(kāi)啟壓縮,防止單個(gè)js文件過(guò)大
(3) 使用webpack構(gòu)建時(shí),推薦使用tree-shaking、prepack插件優(yōu)化js代碼構(gòu)建,縮小體積
(4) 使用innerHTML替代DOM操作,防止頁(yè)面不斷重復(fù)地全局渲染
(5) 使用react、vue等高性能UI構(gòu)建框架,避免直接操作DOM。
(6) 使用jslint等js語(yǔ)法檢查工具,優(yōu)化js代碼
4,圖片資源優(yōu)化
(1) 圖片合并——對(duì)小圖進(jìn)行sprite(雪碧圖)處理
(2) 圖片壓縮——縮小圖片體積
(3) 圖片大小——做圖時(shí)避免單個(gè)圖片過(guò)大,最好能控制在500k以內(nèi)
靜態(tài)資源優(yōu)化推薦的工具:gulp、webpack、fis3
(三) api請(qǐng)求優(yōu)化
api請(qǐng)求,也就是請(qǐng)求后端工程師編寫(xiě)的后臺(tái)接口,如果請(qǐng)求過(guò)程中出現(xiàn)中斷、掛起(無(wú)響應(yīng))、響應(yīng)超時(shí)、響應(yīng)時(shí)間過(guò)長(zhǎng)等問(wèn)題,使得客戶端長(zhǎng)時(shí)間獲取不到數(shù)據(jù),頁(yè)面得不到數(shù)據(jù)填充,也會(huì)造成性能影響。
api請(qǐng)求優(yōu)化主要從兩方面入手,一是客戶端做http請(qǐng)求異常處理,二是后端接口優(yōu)化。
1,http請(qǐng)求異常處理
(1) 請(qǐng)求超時(shí)處理——timeout
當(dāng)http請(qǐng)求超過(guò)限定的時(shí)間后中斷請(qǐng)求,給予用戶相應(yīng)的提示。
(2) 錯(cuò)誤處理
根據(jù)不同的響應(yīng)錯(cuò)誤給予用戶相應(yīng)的提示。
2,后端接口優(yōu)化
(1) 避免無(wú)響應(yīng)的情況發(fā)生
(2) 避免過(guò)度操作復(fù)雜的邏輯
(3) 避免過(guò)度的嵌套查詢
(4) 與前端約定好一套響應(yīng)規(guī)則,包括響應(yīng)狀態(tài)碼、數(shù)據(jù)格式、消息提示等等
(5) 服務(wù)器開(kāi)啟gzip壓縮、以及服務(wù)器緩存
四,其他優(yōu)化
1,服務(wù)器緩存
善用緩存,只加載初始化或有更新?tīng)顟B(tài)的資源,對(duì)無(wú)更新?tīng)顟B(tài)的資源則返回已緩存的結(jié)果。
這樣可實(shí)現(xiàn)快速響應(yīng)請(qǐng)求、減少服務(wù)器帶寬占用和資源浪費(fèi)。
對(duì)于資源的更新,可對(duì)資源添加時(shí)間戳或隨機(jī)字符串的形式來(lái)處理,可參考gulp、webpack版本控制實(shí)現(xiàn)
2,客戶端緩存——cookie、WebStorage
客戶端可對(duì)http請(qǐng)求的結(jié)果進(jìn)行緩存,在數(shù)據(jù)無(wú)更新的狀態(tài)下,可直接使用已緩存的結(jié)果,而不用再次發(fā)出多余的http請(qǐng)求。這對(duì)于一些不變或更新頻率較低的數(shù)據(jù)尤為實(shí)用。
客戶端緩存的方案主要有cookie、WebStorage、Application Cache。善用它們可提高你的應(yīng)用的性能。
3,使用cdn存儲(chǔ)靜態(tài)資源
使用cdn服務(wù)器存儲(chǔ)圖片、文件、音頻/視頻等靜態(tài)資源文件,這樣可避免過(guò)多占用服務(wù)器帶寬和服務(wù)器磁盤(pán)空間。
若配置有不同地域多節(jié)點(diǎn)cdn服務(wù)器,可實(shí)現(xiàn)就近節(jié)點(diǎn)傳輸,加快http請(qǐng)求速度。