90%的人都不知道的前端效能優化技巧(下)
前言
相關概念瞭解請移步 這些前端效能優化的知識我從來不告訴別人(上篇) 本文乾貨居多噢
引言
當遇見“你為效能優化做了哪些事情”,
-
70% 的人上來就說減少合併資源、減少請求、資料快取這些優化手段;
-
15% 的人會提到需要在 DevTools 下先看看首屏時間,圍繞首屏來優化;
-
10%的人會提到需要接入一個性能平臺來看看現狀,診斷一下;
-
而只有 5% 的同學會從前端效能體系來系統考慮效能優化。
你有答案不? 假如你是面試官,或者前端負責人,你會要哪一種人。
毫無疑問,我會想要那5%。本篇文章和上篇不一樣,都是實際乾貨。但還是希望各位看官能先看看上篇,起碼對效能體系能有個模糊的概念。
前端效能體系
舉個栗子。某天你的老闆的老闆跨越層級給你call了電話,問:“我剛開啟首頁很慢,但後面開啟就不會了。這是怎麼回事?使用者是不是也跟我一樣遇到了這樣的問題?”
你老實告訴我,你會如何回答老闆的老闆(例如CEO)? 為了不背很大的鍋,你會不會告訴老闆的老闆,這是使用者網路情況不好導致的?
那更大的問題就來了, 是不是過幾天,或者不定時的就會出現這種情況?你能每次都找到老闆能接受的理由嗎?不,你不能。
首頁開啟緩慢,原因有很多。老闆期待的是,前端能和服務端一樣,通過查查日誌就能定位問題所在。如果你只停留在猜測層面不去解決掉問題,你猜猜你會是什麼下場?實際上,能做到這點的人並不多見。
所以,前端到底有沒有這樣類似服務端的工具呢?有,那就是效能監控平臺。要不,乾脆你來做一個性能監控平臺吧。要求不多,平臺能監控各個業務的效能指標以及在對應場景下的效能標準。當遇到效能問題,你能直接判斷當前表示效能的指標資料意味著什麼。然後平臺會提示你,問題到底是出在前端還是服務端,抑或是網路層的問題。
那什麼是前端效能體系? 你可以初步理解為一堆效能指標的集合,針對集合中的各種元素組合進行監控、預警,甚至報警。
那又要問了,效能指標是怎麼來的?
從 URL 輸入到頁面載入整過程分析
當你在瀏覽器輸入 URL
並回車後,瀏覽器為了把 URL
解析為 IP
地址,會向 DNS
伺服器發起 DNS
查詢來獲取 IP
地址。接著瀏覽器通過 IP
地址找到目標伺服器,發起 TCP
三次握手和 TLS
協商,從而建立起 TCP
連線。
在建立TCP
連線後,瀏覽器發起 HTTP
請求,服務端響應接收到的請求。接著瀏覽器從響應結果中拿到資料,並進行解析和渲染,最後在使用者面前就出現了一個網頁。
所以,前端效能瓶頸點是不是就出現在這個過程中?
客戶端發起請求階段
使用者在瀏覽器輸入 URL
,命中本地快取則直接走快取出頁面。。如果沒有命中快取,會由 DNS
查詢從域名伺服器獲取這個 IP
地址,接下來就是客戶端通過 TCP
的三次握手和TLS協商向伺服器發起 HTTP
請求建立TCP
連線的過程。
諾,這個階段 本地快取
、DNS
查詢、HTTP
請求都能是效能瓶頸點。懂了伐?
-
本地快取
(這點不多說了,免得被部分看官說是“老四樣” /手動捂臉) -
DNS查詢
-
每進行一次 DNS 查詢,都要經歷從手機到移動/電信的訊號塔,再到認證 DNS 伺服器整個過程。關鍵是這個過程時間以及足夠長了,是使用者不能接受的長時間等待。
-
要節省時間,可以讓 DNS 查詢走快取,瀏覽器也提供了 DNS 預獲取的介面。我們可以在開啟瀏覽器或者 WebView 的同時就進行配置。這樣真正發請求時,DNS 域名解析可以檢查一下瀏覽器快取,一旦快取命中,就不需要去 DNS 伺服器查詢了。
-
-
HTTP 請求
- HTTP/1.1 最大的瓶頸是序列的檔案傳輸和同域名的連線數限制。 這裡也不多贅述了,上篇有提到。
服務端處理請求階段
資料快取
- 藉助
Service Worker
的資料介面快取 - 藉助本地儲存的介面快取和
CDN
(Content Delivery Network
,內容分發網路) - 為什麼資料快取會成為效能瓶頸點呢?這是因為每請求一次資料介面,需要從客戶端到後端伺服器,再到更後端的資料儲存層,一層一層返回資料,最後再給到客戶端,耗時很長,如果能夠減少一次這個請求,為首屏時間爭取了寶貴的時間。
- 藉助
重定向
-
所謂重定向,是指網站資源(如表單,整個站點等)遷移到其他位置。使用者在訪問站點時,使用者請求從一個頁面轉移到另外一個頁面的過程。
-
在服務端處理階段,重定向分為三類(都會引起新的DNS查詢,產生新的 HTTP 請求。)
- 服務端發揮的302重定向,
- META 標籤實現的重定向和前端 Javasript
- 通過window.location 實現的重定向。
-
客戶端頁面渲染階段(拿到資料開始渲染頁面)
構建 DOM 樹的瓶頸點
(等待後續Virtual DOM -> 真實DOM 的文章吧)佈局中的瓶頸點
- 例如上篇評論中有童鞋提到的雪碧圖。這裡留個小問題:首頁適合用雪碧圖嗎?
js計算
- 例如紅包雨
- 例如長列表
以上,介紹了前端領域我們能改變的瓶頸點。還有其他方面,我沒有提到。
- 比如,作業系統。 我曾在一個
15
寸的螢幕上做首屏秒開,當時記得是作業系統是Android 5.3
版本。多苦,你想想就明白了。 GPU
、GUI
等。- 網路層和服務層
- 預防阻塞
- 負載均衡
- 慢啟動
- 演算法
- 頁面解析、渲染的演算法
- 標記化演算法
- 樹構建演算法
- GC
- ……
搭建一個性能監控平臺?
現在市場並沒有功能做得很全面的產品。即使有,目前也沒有好的開源專案。但如果僅僅只是正對公司部分業務搭建一個簡單的效能監控平臺是沒有那麼難的。
準備一,做好資料埋點。
目的是為了能獲取到一部分上報資料。例如頁面在1小時內被訪問的次數,頁面出錯的次數,哪些位置、入口點選數最高等等。那說下幾種埋點方式吧。
-
手動埋點(程式碼埋點)
-
純手動寫程式碼,呼叫埋點SDK的函式。在需要埋點的業務邏輯功能位置呼叫介面上報埋點資料。目前市場上第三方資料統計服務商(例如百度)大都採用這種方案;
-
手動埋點的技術本質是什麼呢?它能獲取到哪些內容?
- 域名:document.domainURLdocument.URL
- 頁面標題:document.title
- 解析度:window.screen.height & window.screen.width
- 顏色深度:window.screen.colorDepth
- Referrer:document.referrer
- 客戶端語言:navigator.language
-
埋點做法
// 命令式埋點 ()=>{ // ... 這裡是你的業務邏輯程式碼 sendData(params); //這裡是傳送你的埋點資料,params是你封裝的埋點資料 } // 宣告式埋點 <div data-spm-data="{name:'點選',enevt:'touch',agent: '...'}">Touch</div>
-
-
視覺化埋點
- 解決了純手動埋點的開發成本和更新成本,通過視覺化工具快速配置採集節點(圈點),在前端自動解析配置,並根據配置上傳埋點資料,比起手動埋點看起來更無痕,這裡的配置資料可以設定過濾條件,避免針對所有元素(比如全埋點),可以在呼叫開啟自動監控API時通過設定一些特徵屬性,來過濾不符合條件的元素,實現只針對某些元素進行自動上報資料的需求。(這不多贅述了,細聊內容很多。等以後吧。)
-
無埋點 (wait...)
準備二,定義好效能指標以及量化指標資料
- 指標量化場景
- 弱網情況下
- 無網路情況下
- 機型
- 網路短暫異常
- ……
- 指標
- 頁面白屏時間
- FPS
- 頁面秒開率
- 頁面報錯率
- 頁面卡頓次數
- ……
開發吧。
你啥都搞清楚了,真的可以嘗試開發一個簡易版本的效能監控平臺了。
骨架屏
為什麼要單獨拿出來說。因為,骨架屏可以做一個很重要的效能指標:渲染資料到頁面的時間。
所以,你認為的骨架屏是什麼?例如以下這個樣子?
是的,它是骨架屏。
Q: 骨架屏僅僅只能做到如此嗎? 答: 你錯了。如果骨架屏出現的足夠快,那為什麼我不在骨架屏中加入其它元素呢?舉個栗子。
如圖,這張卡片內容有三部分組成: 商品圖片、商品名稱、立即購買按鈕。假如你的骨架屏能預先拿到文字相關的資料呢? 你是不是可以考慮,把這些商品的名字當中骨架屏的一部分。
事實上,我在做元件骨架屏的時候就發現了這個問題。拋開獲取資料的時間不談,元件骨架屏渲染一個文字節點的時間幾乎可以忽略不計。所以,問題就轉移到了資料上。那假如你把資料本地快取了一份?
再假設一下,假如圖片骨架屏也能預先拿到圖片資料呢? 那是不是也可以嘗試去渲染圖片呢?
這裡要被問到了,那做了這些還算是骨架屏嗎?那我們是不是可以對骨架屏有另一個認知:只要沒有繫結JS事件的元素都可以看作是骨架。
人有美醜,為什麼骨架屏不能有? 那麼這裡又會有人槓了。你這又是資料快取又是懶載入的,骨架屏需要這些嗎?
那麼,什麼是骨架屏。 骨架屏的本質是不是對你的元件自動生成一套骨架? 至於生成什麼樣的骨架,你管我?我有效能監測平臺的好不啦? 平臺告訴我,我的頁面秒卡率大幅增加了好不啦?
所以,最重要一點,即使很多人認為前端效能優化一提到就是老四樣,你依然可以玩出花來。畢竟,實踐出真知。
快照
快照是一個很有意思的事情。例如天貓,你下單的時候會給你生成交易快照,後面的所有流程都以交易快照的資料為準,保證你的錢不會後期被多花或者少花。 比較價格這種東西,變一變很正常。
還有一種快照的解釋。例如手機截圖,把當前使用者看到的頁面內容生成一張圖片儲存到相簿中。
那,這裡我說一種。將你的首頁做一份快照,備份到native快取裡,每次進來先載入那份快照。這份快照就是index.html檔案,放native包的本地快取裡。你覺得瀏覽器直接訪問你的index.html快嘛?
又得要槓了。這怎麼有點像SSR? SSR理,服務端會給客戶端傳送一份包含html的模版字串,可以沒有樣式,可以沒有js。但快照有樣式,就跟擺了張圖片覆蓋在首頁一樣。那你覺得是渲染一張足以覆蓋首頁的圖片快,還是訪問一份index.html快?
預渲染
先解釋下預渲染的本質吧。提前準備好以下兩點:
- index.html + js + css
- data (JSON)
再上張圖吧。
(圖片來自於網路,如有侵權請聯絡刪除)
結合圖片描述,再來認真解釋一下。
預渲染是指在使用者訪問這個頁面之前,完成頁面渲染的準備。 簡單點說就是在使用者訪問頁面之前,我將頁面內容存放在使用者看不見的地方,待使用者需要看見內容的時候再把已經渲染完畢的內容挪到能看見的位置。
稍微總結下。
- 在使用者正式訪問頁面之前,要將頁面的內容渲染完畢。
- 在使用者正式訪問的時候,只需直接載入已經渲染好的內容。
具體咋實現呢?
NSR
(Native side rendering
,客戶端渲染)
通過客戶端(Native
)進行頁面結構拼接,進而實現頁面渲染的處理技術。
需要離線包提供模板等資源(如 HTML、JS、CSS
)。預載入提供資料,把頁面作為資料經過模板函式變化後產生的結果,然後通過 v8 引擎在客戶端渲染出來。
預載入
提前將資料準備好。例如在使用者訪問之前就將介面快取下來,呼叫介面後把得到的data也快取下來。
NSR 是怎麼實現的呢?
- 首先是模板和資料必須準備好,保證使用者點選頁面連結進入後,這個頁面的所有資源是準備好的。至於咋做,可以看一下(上篇)
- 離線化
- 預載入
- 快取
-
因為頁面是動態的, URL 是靜態的,我們需要實現一種頁面與模版的對映機制,一般為多對一。 這個機制有助於 Native 快速定位到使用者所需的模版。
-
在
Native
端實現本地渲染服務。(這點有點類似SSR,關於SSR詳細內容等待後續文章)。 -
The End. 搞完 NSR 之後,前端程式碼並不需要做什麼改動,只需要把後置流程準備好就可以了。後置流程指的就是指將渲染好的頁面後放置在可視區域之外。
小結一下
每個公司環境都不一樣,每一種技術方案並不一定需要完全實現,如果實現一部分就能效能達標,那就沒必要花更多的成本去做剩下的事情。 其實,webpack做的預渲染更好理解一些。 程式碼貼出來給大家看看,小夥伴也可以去上篇看更詳細的。
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' ]
)
]
}
最後
為了幫助大家更好溫習重點知識、更高效的準備面試,特別整理了《前端工程師面試手冊》電子稿檔案。
內容包括html,css,JavaScript,ES6,計算機網路,瀏覽器,工程化,模組化,Node.js,框架,資料結構,效能優化,專案等等。(本文資料 適合0-2年)
包含了騰訊、位元組跳動、小米、阿里、滴滴、美團、58、拼多多、360、新浪、搜狐等一線網際網路公司面試被問到的題目,涵蓋了初中級前端技術點。
前端面試題彙總
JavaScript
效能
linux
前端資料彙總
完整版PDF資料免費分享,只需你點贊支援,動動手指點選此處就可免費領取了。
最後送給大家一句話:
“在某個階段,你之前積累的東西會以某種自己未曾想到過的方式連線起來,最終是這些經歷成就了一個人。這種機會是不可預知(而且非常有樂趣)的,但只會留給默默耕耘的人。”
你需要的只是勇敢的邁出第一步,然後不斷的優化自己,總結自己,你一定會拿到你屬於自己的offer。