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