您好,登錄后才能下訂單哦!
這篇文章給大家分享的是有關(guān)前端性能優(yōu)化的示例分析的內(nèi)容。小編覺(jué)得挺實(shí)用的,因此分享給大家做個(gè)參考,一起跟隨小編過(guò)來(lái)看看吧。
反復(fù)看下以下三個(gè)問(wèn)題。
有木有不同的人問(wèn)過(guò)你:什么是前端性能優(yōu)化?
有木有不同的面試官問(wèn)過(guò)你:你為前端性能優(yōu)化做過(guò)什么?
有木有哪一次,你問(wèn)過(guò)自己:別人問(wèn)我前端性能優(yōu)化到底應(yīng)該如何答復(fù)?
你有木有一套自己的關(guān)于性能優(yōu)化的答案,能讓技術(shù)大牛和你一起探討,也能讓小白點(diǎn)頭稱是。
假如你有,那你的答案在哪。
例如整個(gè)天貓首頁(yè)。答案有很多種,你看看有木有你想的那種。
create-react-app
初始化一個(gè)項(xiàng)目吧。 首頁(yè)寫好一些組件,例如豆腐塊、Header、Bar
、長(zhǎng)滾動(dòng)ScrollView
。然后項(xiàng)目編譯、打包上線。
webpack
手搭一個(gè)項(xiàng)目。
路由按需加載弄上,可無(wú)痕瀏覽的帶loadmore
的高性能ScrollList
。
因?yàn)槭鞘醉?yè),明顯會(huì)牽扯到首屏幕加載的問(wèn)題。那骨架屏給安排上吧。
再搞一套webpack的最佳實(shí)踐,目的是能最終得到體積盡量小的打包文件。
SSR來(lái)一套吧。因?yàn)槭醉?yè)DOM結(jié)構(gòu)太復(fù)雜了,如果走Virtual DOM
那一套,等到GPU渲染UI就太慢了。
以上,有命中你的某個(gè)點(diǎn)嗎? 不管有木有道理,這是你想到的點(diǎn)嗎?是不是總感覺(jué)好像少了點(diǎn)什么?
本篇文章不細(xì)講其它內(nèi)容。 但到這了就得提一嘴,留個(gè)印象。
系統(tǒng)層設(shè)計(jì)
一個(gè)新系統(tǒng)留20%來(lái)滿足當(dāng)前已有業(yè)務(wù)。 剩下80% 用來(lái)系統(tǒng)演進(jìn)??梢运伎枷?,天貓首頁(yè)一直變,卻依然能保證性能達(dá)標(biāo)。
業(yè)務(wù)層設(shè)計(jì)
已有業(yè)務(wù)是否與其它業(yè)務(wù)產(chǎn)生了耦合,是否存在前置業(yè)務(wù),如果有那前置業(yè)務(wù)的權(quán)限又在哪里。已有業(yè)務(wù)是否能根據(jù)系統(tǒng)演進(jìn)程度不斷兼容新業(yè)務(wù)?
應(yīng)用層設(shè)計(jì)
例如微前端,例如組件庫(kù),例如
npm install
webpack優(yōu)化
骨架屏
路有動(dòng)態(tài)按需加載
代碼層設(shè)計(jì)
寫好高性能React 代碼?如何利用好Vue3 時(shí)間切片?
不說(shuō)了。太初級(jí)的浪費(fèi)慢慢積累就好。
所以,你應(yīng)該發(fā)現(xiàn)了“總感覺(jué)好像少了點(diǎn)什么” 是少在哪里了。對(duì),前端性能優(yōu)化不僅僅是應(yīng)用層面、代碼層的優(yōu)化,更重要的是系統(tǒng)層、業(yè)務(wù)層的優(yōu)化。
看了以上的心理預(yù)設(shè),那接下來(lái)就進(jìn)入正式進(jìn)入主題吧。
嘗試著走完下面這個(gè)流程:
性能指標(biāo)設(shè)定(FPS、頁(yè)面秒開(kāi)率、報(bào)錯(cuò)率、請(qǐng)求數(shù)等)
如何讓老板了解你的優(yōu)化方案?假如你的老板不懂技術(shù)。
告訴老板,頁(yè)面白屏?xí)r間減少了0.4s。
告訴老板,弱網(wǎng)情況下首頁(yè)秒開(kāi)。
告訴老板,以前http請(qǐng)求量大導(dǎo)致服務(wù)器壓力太大了,現(xiàn)在每個(gè)頁(yè)面最多只有不到5個(gè)請(qǐng)求是向服務(wù)器要資源的。
告訴老板……
性能標(biāo)準(zhǔn)確定
確認(rèn)要哪些指標(biāo)
收益評(píng)估
面向老板滿意編程。 /捂臉.png (手動(dòng)狗頭)
診斷清單
清單上會(huì)告訴你各項(xiàng)指標(biāo)的數(shù)據(jù)。
優(yōu)化手段
WebView 性能優(yōu)化
并行初始化
資源預(yù)加載
數(shù)據(jù)接口請(qǐng)求優(yōu)化
前端架構(gòu)性能調(diào)優(yōu)
長(zhǎng)列表性能優(yōu)化
打包優(yōu)化
組件骨架屏
圖片骨架屏
懶加載
緩存
離線化
并行化
保證首次加載為秒開(kāi)的離線包設(shè)計(jì)
App 啟動(dòng)階段的優(yōu)化方案
頁(yè)面白屏階段的優(yōu)化方案
首屏渲染階段的優(yōu)化方案
Hybrid APP 性能優(yōu)化
首評(píng)秒開(kāi)的X種方法?
骨架屏
NSR
SSR
webView
層及代碼架構(gòu)層面優(yōu)化
性能立項(xiàng)
確定了就去搞起來(lái)吧。
性能實(shí)踐
做好準(zhǔn)備,盡情的在各種惡劣環(huán)境下把頁(yè)面快速的折騰出來(lái)吧!
現(xiàn)在,你對(duì)前端性能優(yōu)化有了一個(gè)完整的認(rèn)知了嗎?很多時(shí)候談?wù)摰叫阅軆?yōu)化首先需要談到如何對(duì)性能進(jìn)行“確診”。雖然大部分情況,你不會(huì)被人問(wèn)到是如何對(duì)性能進(jìn)行監(jiān)控的。(說(shuō)話聲音越來(lái)越小。。。)
接下來(lái)就細(xì)談優(yōu)化手段
最常見(jiàn)的優(yōu)化手段之一。
懶加載是指在長(zhǎng)頁(yè)面加載過(guò)程時(shí),先加載關(guān)鍵內(nèi)容,延遲加載非關(guān)鍵內(nèi)容。比如當(dāng)我們打開(kāi)一個(gè)頁(yè)面,它的內(nèi)容超過(guò)了瀏覽器的可視區(qū)口大小,我們可以先加載前端的可視區(qū)域內(nèi)容,剩下的內(nèi)容等它進(jìn)入可視區(qū)域后再按需加載。
舉個(gè)栗子。天貓首頁(yè)精選。上圖。
正好是天貓618活動(dòng)。這個(gè)IOS版的天貓首頁(yè)精選。如果你經(jīng)常訪問(wèn)天貓首頁(yè)精選,你會(huì)發(fā)現(xiàn)它已經(jīng)幾乎做到了無(wú)痕瀏覽。懶加載在這就被運(yùn)用的很好,當(dāng)然,這里不僅僅是做了懶加載才達(dá)到這樣的效果。
那只說(shuō)懶加載,天貓首頁(yè)精選做了什么呢? 猜猜看。
懶加載
圖片懶加載
圖片是native
做過(guò)緩存的。
在可視區(qū)域出現(xiàn)才會(huì)加載
卡片預(yù)先加載(懶加載的時(shí)機(jī)改變)
并不是進(jìn)入可視區(qū)域才加載卡片的。而是當(dāng)上一張卡片進(jìn)入可視區(qū)域就預(yù)先加載下一張卡片。 因?yàn)橄鄬?duì)于圖片,加載卡片UI會(huì)快得多。 這也是無(wú)痕瀏覽的保障之一。
動(dòng)畫懶加載
假如你快速的進(jìn)行劃屏滾動(dòng),List
滾動(dòng)高度發(fā)生很大變化,那請(qǐng)求數(shù)據(jù)最終還是會(huì)敵不過(guò)你的高速滑動(dòng)。也就是說(shuō),在沒(méi)有新的數(shù)據(jù)之前你看不到下一張卡片了,這是你必須等待了。這時(shí)候就會(huì)有一個(gè)loading
的動(dòng)畫顯示,接著等拿到了新數(shù)據(jù),新卡片就會(huì)出現(xiàn)并且自動(dòng)完全滑入可視區(qū)域。
這里會(huì)有人說(shuō)了,IOS
的阻尼本來(lái)就會(huì)使得動(dòng)畫、滾動(dòng)效果更加順暢。在這里為想說(shuō)的是,Android
也一樣可以。
如果說(shuō)懶加載本質(zhì)是提供首屏后請(qǐng)求非關(guān)鍵內(nèi)容的能力,那么緩存則是賦予二次訪問(wèn)不需要重復(fù)請(qǐng)求的能力。在首屏優(yōu)化方案中,接口緩存和靜態(tài)資源緩存起到中流砥柱的作用。
回到剛才懶加載提到的那個(gè)問(wèn)題,為什么你要快速劃屏一段時(shí)間才會(huì)遇見(jiàn)沒(méi)有新數(shù)據(jù)的情況?原因就是緩存的數(shù)據(jù)已經(jīng)用完了,所以只能讓服務(wù)器給予最新的數(shù)據(jù)。
接口緩存接口緩存的實(shí)現(xiàn),如果是端內(nèi)的話,所有請(qǐng)求都走 Native 請(qǐng)求,以此來(lái)實(shí)現(xiàn)接口緩存。為什么要這么做呢?
App 中的頁(yè)面展現(xiàn)有兩種形式,使用 Native 開(kāi)發(fā)的頁(yè)面展現(xiàn)和使用 H5 開(kāi)發(fā)的頁(yè)面展現(xiàn)。如果統(tǒng)一使用 Native 做請(qǐng)求的話,已經(jīng)請(qǐng)求過(guò)的數(shù)據(jù)接口,就不用請(qǐng)求了。而如果使用 H5 請(qǐng)求數(shù)據(jù),必須等 WebView 初始化之后才能請(qǐng)求(也就是串行請(qǐng)求),而 Native 請(qǐng)求時(shí),可以在 WebView 初始化之前就開(kāi)始請(qǐng)求數(shù)據(jù)(也就是并行請(qǐng)求),這樣能有效節(jié)省時(shí)間。
那么,如何通過(guò) Native 進(jìn)行接口緩存呢?我們可以借助 SDK 封裝來(lái)實(shí)現(xiàn),即修改原來(lái)的數(shù)據(jù)接口請(qǐng)求方法,實(shí)現(xiàn)類似 Axios 的請(qǐng)求方法。具體來(lái)說(shuō)就是,把包括 post、Get 和 Request 功能的接口,封裝進(jìn) SDK 中。
這樣,客戶端發(fā)起請(qǐng)求時(shí),程序會(huì)調(diào)用 SDK.axios 方法,WebView 會(huì)攔截這個(gè)請(qǐng)求,去查看 App 本地是否有數(shù)據(jù)緩存,如果有的話,就走接口緩存,如果沒(méi)有的話,先向服務(wù)端請(qǐng)求數(shù)據(jù)接口,獲取接口數(shù)據(jù)后存放到 App 緩存中。
靜態(tài)資源緩存先看圖。
91 requests,113 kB transferred, 2.2 MB resources,Finish: 2.93 s,DOMContentLoaded: 177 ms.
2.2M的資源,達(dá)到秒開(kāi)。看看Size那一列,你就應(yīng)該好像領(lǐng)悟到什么了。
沒(méi)錯(cuò)。HTTP緩存。 數(shù)據(jù)接口的請(qǐng)求一般來(lái)說(shuō)較少,只有幾個(gè),而靜態(tài)資源(如 JS、CSS、圖片和字體等)的請(qǐng)求就太多了。以天貓首頁(yè)為例,91 個(gè)請(qǐng)求中除了少數(shù)script外,其余都是靜態(tài)資源請(qǐng)求。
那么,如何做靜態(tài)緩存方案呢?這里有兩種情況,一種是靜態(tài)資源長(zhǎng)期不需要修改,還有一種是靜態(tài)資源修改頻繁的。你可以嘗試多刷新幾次頁(yè)面看看。
資源長(zhǎng)期不變的話,比如 1 年都不怎么變化,我們可以使用強(qiáng)緩存,如 Cache-Control 來(lái)實(shí)現(xiàn)。具體來(lái)說(shuō)可以通過(guò)設(shè)置 Cache-Control:max-age=31536000,來(lái)讓瀏覽器在一年內(nèi)直接使用本地緩存文件,而不是向服務(wù)端發(fā)出請(qǐng)求。
至于第二種,如果資源本身隨時(shí)會(huì)發(fā)生改動(dòng)的,可以通過(guò)設(shè)置 Etag 實(shí)現(xiàn)協(xié)商緩存。具體來(lái)說(shuō),在初次請(qǐng)求資源時(shí),設(shè)置 Etag(比如使用資源的 md5 作為 Etag),并且返回 200 的狀態(tài)碼,之后請(qǐng)求時(shí)帶上 If-none-match 字段,來(lái)詢問(wèn)服務(wù)器當(dāng)前版本是否可用。如果服務(wù)端數(shù)據(jù)沒(méi)有變化,會(huì)返回一個(gè) 304 的狀態(tài)碼給客戶端,告訴客戶端不需要請(qǐng)求數(shù)據(jù),直接使用之前緩存的數(shù)據(jù)即可。當(dāng)然,這里還涉及 WebView相關(guān)的東西,先不細(xì)講。。。
離線化是指線上實(shí)時(shí)變動(dòng)的資源數(shù)據(jù)靜態(tài)化到本地,訪問(wèn)時(shí)走的是本地文件的方案。
離線包
就是一是離線化的一種方案,是將靜態(tài)資源存儲(chǔ)到 App 本地的方案,這里先不細(xì)講。
但更復(fù)雜的另一種離線化方案:把頁(yè)面內(nèi)容靜態(tài)化到本地。離線化一般適合首頁(yè)或者列表頁(yè)等不需要登錄頁(yè)面的場(chǎng)景,同時(shí)能夠支持 SEO 功能。
那么,如何實(shí)現(xiàn)離線化呢?在打包構(gòu)建時(shí)預(yù)渲染頁(yè)面,前端請(qǐng)求落到 index.html 上時(shí),已經(jīng)是渲染過(guò)的內(nèi)容。此時(shí),可以通過(guò) Webpack 的 prerender-spa-plugin 來(lái)實(shí)現(xiàn)預(yù)渲染,進(jìn)而實(shí)現(xiàn)離線化。
Webpack 實(shí)現(xiàn)預(yù)渲染的代碼示例如下:
// webpack.conf.js var path = require('path') var PrerenderSpaPlugin = require('prerender-spa-plugin') module.exports = { // ... plugins: [ new PrerenderSpaPlugin( // 編譯后的html需要存放的路徑 path.join(__dirname, '../dist'), // 列出哪些路由需要預(yù)渲染 [ '/', '/about', '/contact' ] ) ] } // 面試的時(shí)候離線化能講到這,往往就是做死現(xiàn)場(chǎng),但風(fēng)險(xiǎn)和收益成正比,值得冒險(xiǎn)。那就是,你有木有自己的預(yù)渲染方案。
如果說(shuō)懶加載、緩存和離線化都是在請(qǐng)求本身搞事情,想盡辦法減少請(qǐng)求或者推遲請(qǐng)求,那并行化則是在請(qǐng)求通道上優(yōu)化問(wèn)題,解決請(qǐng)求阻塞問(wèn)題,進(jìn)而減少首屏?xí)r間。
例如廣州打疫苗排隊(duì),新聞上報(bào)道是如何如何阻塞。 那除了讓群眾錯(cuò)開(kāi)打疫苗的時(shí)間,還可以增加打疫苗的醫(yī)生數(shù)量。我們?cè)谔幚碚?qǐng)求阻塞時(shí),也可以加大請(qǐng)求通道數(shù)量——借助于HTTP 2.0
的多路復(fù)用方案來(lái)解決。
HTTP 1.1
時(shí)代,有兩個(gè)性能瓶頸點(diǎn),串行的文件傳輸和同域名的連接數(shù)限制(6個(gè)
)。到了HTTP 2.0
時(shí)代,因?yàn)樘峁┝硕嗦窂?fù)用的功能,傳輸數(shù)據(jù)不再使用文本傳輸(文本傳輸必須按順序傳輸,否則接收端不知道字符的順序),而是采用二進(jìn)制數(shù)據(jù)幀和流的方式進(jìn)行傳輸。
其中,幀是數(shù)據(jù)接收的最小單位,流是連接中的一個(gè)虛擬通道,它可以承載雙向信息。每個(gè)流都會(huì)有一個(gè)唯一的整數(shù) ID 對(duì)數(shù)據(jù)順序進(jìn)行標(biāo)識(shí),這樣接收端收到數(shù)據(jù)后,可以按照順序?qū)?shù)據(jù)進(jìn)行合并,不會(huì)出現(xiàn)順序出錯(cuò)的情況。所以,在使用流的情況下,不論多少個(gè)資源請(qǐng)求,只要建立一個(gè)連接即可。
文件傳輸環(huán)節(jié)問(wèn)題解決后,同域名連接數(shù)限制問(wèn)題怎么解決呢?以 Nginx 服務(wù)器為例,原先因?yàn)槊總€(gè)域名有6
個(gè)連接數(shù)限制,最大并發(fā)就是 100
個(gè)請(qǐng)求,采用 HTTP 2.0
之后,現(xiàn)在則可以做到 600
,提升了 6
倍。
你一定會(huì)問(wèn),這不是運(yùn)維側(cè)要做的事情嗎,我們前端開(kāi)發(fā)需要做什么?我們要改變靜態(tài)文件合并(JS、CSS、圖片文件)和靜態(tài)資源服務(wù)器做域名散列這兩種開(kāi)發(fā)方式。
具體來(lái)說(shuō),使用 HTTP 2.0
多路復(fù)用之后,單個(gè)文件可以單獨(dú)上線,不需要再做 JS 文件合并了。這里提一個(gè)保留問(wèn)題,用過(guò)阿里系的Antd組件庫(kù)吧?庫(kù)每次更新都不是全部更新,可能這次只更新一個(gè)Button
組件,再次只更新一個(gè)Card
組件。那是如何做到單獨(dú)組件單獨(dú)發(fā)版的呢?
為了解決靜態(tài)域名阻塞(這是個(gè)性能瓶頸點(diǎn)),需要將靜態(tài)域名分為 pic0-pic5,這樣能提升請(qǐng)求并行能力。
雖然通過(guò)靜態(tài)資源域名散列的辦法解決了問(wèn)題,但DNS 解析時(shí)間會(huì)變長(zhǎng)很多,同時(shí)還需要額外的服務(wù)器來(lái)滿足。HTTP 2.0
多路復(fù)用解決了這個(gè)問(wèn)題。
感謝各位的閱讀!關(guān)于“前端性能優(yōu)化的示例分析”這篇文章就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,讓大家可以學(xué)到更多知識(shí),如果覺(jué)得文章不錯(cuò),可以把它分享出去讓更多的人看到吧!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。