什么是性能拯刁?前端業(yè)務(wù)開發(fā)關(guān)注的性能,主要有兩個(gè):加載速度逝段、渲染效率垛玻。二者一般也合稱【性能體驗(yàn)】割捅。
加載速度
衡量加載速度的傳統(tǒng)指標(biāo)一般是:首字節(jié)、DOMContentLoaded帚桩、onLoad亿驾。傳統(tǒng)指標(biāo)的問題是,完全站在技術(shù)視角衡量账嚎,并不能代表用戶實(shí)際的體驗(yàn)莫瞬。目前受業(yè)界廣泛認(rèn)可的是谷歌提出的一套面向用戶的指標(biāo) Progressive Web Metrics :
- FP(First Paint)白屏結(jié)束,有可見像素出現(xiàn)了
- FCP(First Contentful Paint)對(duì)用戶有意義的內(nèi)容出現(xiàn)了
- FMP(First Meaningful Paint)同上
- TTI(Time to Interactive)js 執(zhí)行完了郭蕉,可以交互了
FP 定義了【白屏?xí)r間】疼邀,后面兩個(gè)定義【首屏?xí)r間】。從技術(shù)角度看怎么知道什么是 Contentful恳不,什么是 Meaningful檩小?基本策略是檢測(cè) DOM 節(jié)點(diǎn)變化最大的時(shí)刻,不過最精確的還是得靠自定義埋點(diǎn)烟勋,畢竟這個(gè)指標(biāo)歸根結(jié)底是用于幫助開發(fā)掌握頁(yè)面在線上運(yùn)行的實(shí)際狀況规求,也只有開發(fā)最清楚頁(yè)面內(nèi)容的加載過程。TTI 最好也用自定義埋點(diǎn)卵惦,靠技術(shù)手段檢測(cè)會(huì) 比較麻煩 阻肿。
在實(shí)踐中,我們需要在 關(guān)鍵路徑 上的各個(gè)節(jié)點(diǎn)添加監(jiān)控埋點(diǎn)沮尿,從 url 發(fā)出請(qǐng)求丛塌,到 DNS 解析,到服務(wù)端處理(如果是服務(wù)端渲染的話)畜疾,到 html 開始加載赴邻,到阻塞類資源加載,到業(yè)務(wù)代碼開始執(zhí)行啡捶,到接口返回姥敛,到內(nèi)容正式渲染。這樣才有利于分析究竟是哪個(gè)環(huán)節(jié)影響了最終性能瞎暑。
張克軍的這張圖描繪了網(wǎng)頁(yè)通用的加載模型彤敛,在實(shí)際業(yè)務(wù)中通常還存在其他一些環(huán)節(jié)。比如移動(dòng)端 hybrid 頁(yè)面或 RN 頁(yè)面的容器初始化過程了赌,比如前置校驗(yàn)用戶登錄態(tài)墨榄、獲取用戶定位等等。
上述指標(biāo)只是衡量了單個(gè)頁(yè)面的性能勿她,看不到產(chǎn)品整體的性能袄秩,因此大廠基本都在搞一個(gè)叫【秒開率】的指標(biāo)。秒開率是指整個(gè)樣本集中,某指標(biāo)小于 1s 的占比之剧。秒開率回答了這樣一個(gè)問題:整個(gè)產(chǎn)品有多少頁(yè)面的性能指標(biāo)(一般取 90 分位線)小于 1s贮喧。
渲染效率
渲染效率就是指頁(yè)面流暢度,看交互動(dòng)效是否有卡頓(掉幀)猪狈。衡量渲染效率的指標(biāo)主要是 FPS箱沦。查看 FPS 最簡(jiǎn)單的辦法有兩個(gè),一是用 stats.js 雇庙,二是在 chrome devtools 中通過 command + shift + p 調(diào)出命令窗口谓形,輸入 fps 即可調(diào)出幀率面板。
由于 UI 線程和 js 線程共用同一個(gè)線程疆前,js 任務(wù)的運(yùn)行可能導(dǎo)致 UI 卡頓寒跳、卡死,因此瀏覽器還提供了一個(gè)用于監(jiān)控 long task 的 api竹椒。
參考: 百度APP流暢度全流程質(zhì)量監(jiān)控實(shí)踐(一) 流暢度現(xiàn)狀分析 童太。
監(jiān)控
通常我們發(fā)現(xiàn)某個(gè)頁(yè)面性能已經(jīng)很差了,于是一頓專項(xiàng)優(yōu)化胸完,最后各項(xiàng)指標(biāo)都達(dá)到了預(yù)設(shè)目標(biāo)书释,但問題是怎么保證性能長(zhǎng)期不會(huì)繼續(xù)劣化呢?為了知道頁(yè)面在線上運(yùn)行的實(shí)際性能狀況赊窥,首先就得把監(jiān)控體系建立起來爆惧,能對(duì)采集到的指標(biāo)數(shù)據(jù)做各種聚合展示以便隨時(shí)看到頁(yè)面指標(biāo)數(shù)據(jù)變化,能定期自動(dòng)生成報(bào)表锨能,能對(duì)指標(biāo)異常變化(比如突增扯再、驟降)添加報(bào)警。
為了采集性能數(shù)據(jù)址遇,瀏覽器提供了一系列專門用于監(jiān)控性能的 API熄阻,例如 navigation-timing、 resource-timing 倔约、 user-timing 等秃殉。通用指標(biāo)可封裝 sdk 進(jìn)行采集上報(bào),sdk 應(yīng)該同時(shí)提供上報(bào)自定義測(cè)速點(diǎn)的能力跺株。
除了線上監(jiān)控复濒,性能保障還有賴于事前防控脖卖。比如在上線流程乒省,應(yīng)該有一道性能檢測(cè)環(huán)節(jié)(checklist),防止一些明顯的畦木、常見的袖扛、比較極端的性能劣化場(chǎng)景,比如上了一個(gè)特別大的資源而不自知(不小心全量引入了 lodash、加了張沒壓縮的大圖蛆封、引入了無用的資源等)唇礁。最簡(jiǎn)單的思路,就是上傳到 ligthouse惨篱,如果檢測(cè)得分低于閾值盏筐,就直接禁止上線。這種檢測(cè)既可以在上線前執(zhí)行砸讳,也可以定期循環(huán)執(zhí)行琢融。
性能分析
通常監(jiān)控已經(jīng)能提供比較詳細(xì)的性能狀況數(shù)據(jù),不過排查問題時(shí)通常還需要一些工具輔助以獲得更加細(xì)節(jié)的信息簿寂。
瀏覽器提供了一系列衡量性能的工具漾抬,可查看 資源加載時(shí)序 、 分析網(wǎng)頁(yè)性能 常遂、 分析代碼執(zhí)行耗時(shí) 纳令、 分析渲染流暢度 等。
現(xiàn)代框架一般也提供了運(yùn)行時(shí)的性能分析工具克胳。比如 react profiler 平绩,可方便的看到組件級(jí)乃至方法級(jí)的執(zhí)行耗時(shí)(針對(duì)【渲染效率】)。
其他分析工具
加載性能優(yōu)化
性能優(yōu)化的基本思路漠另,是搞清楚整個(gè)加載鏈路出問題的環(huán)節(jié)馒过,然后針對(duì)性的修復(fù)。具體的手段酗钞,主要有四種類型:
- 體量規(guī)劃
- 時(shí)序規(guī)劃
- 距離規(guī)劃
- 定向優(yōu)化
其實(shí)還有一種嚴(yán)格說只能算體驗(yàn)優(yōu)化的手段腹忽,就是從交互上讓用戶感覺得快,比如骨架屏砚作,還有圖片的漸進(jìn)式加載(可參考 how medium does progressive image loading )窘奏。
體量規(guī)劃
通常來說,加載資源的總量越小葫录,加載性能越好着裹。針對(duì) web 而言,主要是限制請(qǐng)求資源的體積米同。單從資源體積的角度看骇扇,理想情況是完全的按需加載,即每時(shí)每刻僅加載當(dāng)前需要的資源面粮。
- 只請(qǐng)求當(dāng)前環(huán)境需要的資源
- 增量加載(懶加載少孝、漸進(jìn)式加載、異步加載熬苍、分屏加載...)
- 按需加載 polyfill
- modern 構(gòu)建模式
- 減小資源體積(雅虎14條之4稍走、10)
- uglify
- Gzip(服務(wù)端開啟袁翁,只壓縮文本文件,不要壓縮圖片這類的二進(jìn)制文件婿脸, 原因 )
- 圖片優(yōu)化(壓縮粱胜、像移動(dòng)端一樣針對(duì)屏幕尺寸和分辨率加載不同大小/質(zhì)量的圖片、根據(jù)網(wǎng)絡(luò)狀況加載不同質(zhì)量的圖片狐树、用 webp 格式)
- 控制 cookie 大小
- 控制 header 大小
- 用字符數(shù)最少的代碼:例如用 void 0 代替 undefined
- 減小無效資源(雅虎14條之4焙压、12)
- 刪除無效的代碼(Dead Code Elimination)
- 刪除重復(fù)代碼( js-copypaste-detect )
- 移動(dòng)端字體圖標(biāo)只需要用 ttf
- 避免空 src
時(shí)序規(guī)劃
小學(xué)奧數(shù)里有個(gè)主題叫統(tǒng)籌規(guī)劃,其中有一類問題就是看如何安排各種事情的執(zhí)行流抑钟,以最小化總時(shí)間冗恨。時(shí)序規(guī)劃也是類似,最基本的兩種思路味赃,就是并發(fā)和前置掀抹,要么一起搞,要么提前搞心俗。
- 并行
- Promise.all
- facebook BigPipe
- 前置
- SSR:將模板渲染前置到服務(wù)端處理
- prefetch傲武、prerender、preload
- 容器預(yù)初始化
- 管道:無需等所有數(shù)據(jù)加載完才處理城榛,而是加載一部分就處理一部分(html 的渲染就是這樣的)
距離規(guī)劃
距離規(guī)劃的基本原理是:傳輸速度有上限揪利,因此距離越近,時(shí)間越短狠持。距離最近的是寄存器/內(nèi)存疟位,最遠(yuǎn)的是服務(wù)器。
- CDN (雅虎14條之2)
- 緩存
- http 緩存(雅虎14條之3喘垂、13)
- 使用可緩存的 get 請(qǐng)求(雅虎14條之14)
- 服務(wù)器緩存
- localStorage
- web worker
- kv-storage
- stale-while-revalidate
- 避免重定向(雅虎14條之11)
- 服務(wù)端推送(單向傳輸甜刻,避免一來一回)
通常能夠被緩存并且緩存能起到較大作用的,是不常變化正勒、會(huì)被反復(fù)用到的靜態(tài)信息得院。經(jīng)常變化的信息,或者很少重復(fù)使用的信息章贞,會(huì)影響緩存的命中率祥绞。要利用緩存,在設(shè)計(jì)上就需要考慮 動(dòng)靜分離 鸭限,比如與用戶狀態(tài)無關(guān)的配置信息和與用戶狀態(tài)相關(guān)的動(dòng)態(tài)信息分開使用不同接口蜕径。
為了讓經(jīng)常變化的數(shù)據(jù)也能使用緩存來提高效率,也有一種思路:每次都先從緩存里取數(shù)據(jù)败京,然后每次都發(fā)送請(qǐng)求更新緩存兜喻,以時(shí)間換空間,以 1 次延遲的代價(jià)喧枷,來提高接口請(qǐng)求的性能虹统。這種策略還有個(gè)專門的規(guī)范叫 stale-while-revalidate ,基于 react hook 實(shí)現(xiàn)的網(wǎng)絡(luò)請(qǐng)求方法庫(kù) swr 已經(jīng)內(nèi)置了該策略隧甚。
定向優(yōu)化
前三種思路屬于通用思路车荔,比如 CPU 的性能優(yōu)化也會(huì)采用這些思路。而定向優(yōu)化是指針對(duì)環(huán)境的特征戚扳,提供專門的優(yōu)化方案忧便。就 Web 而言,特定環(huán)境主要是指:瀏覽器的請(qǐng)求帽借、加載和渲染機(jī)制珠增;http 協(xié)議;js 引擎砍艾。
針對(duì)瀏覽器機(jī)制
- 域名分片(Domain Sharding蒂教、SPDY)
- 因?yàn)闉g覽器對(duì)單個(gè)域名的并發(fā)加載數(shù)有上限,一般是 6 個(gè)
- PC 端可分片 2-4 個(gè)為宜
- 移動(dòng)端 DNS 解析很慢脆荷,分片不要超過 2 個(gè)
- 針對(duì)加載過程的優(yōu)化
針對(duì) http 1.1
- 減少請(qǐng)求次數(shù)(雅虎14條之1)
- 合并資源(bundle / spites)或合并資源的請(qǐng)求(CDN Combo)
- 合并多個(gè) ajax 請(qǐng)求
- CSS inline
- 使用 CSS、SVG蜓谋、Inline Image梦皮、Icon-font 代替圖片
- 避免使用 @import 和 iframes
- 控制域名數(shù)量,減少 DNS 查詢(雅虎14條之9)
- 選擇更先進(jìn)的協(xié)議:UDP桃焕、QUIC剑肯、SPDY、http 2
- 《Web 性能權(quán)威指南》
針對(duì) js 引擎
- 使用更高效的 api
- jsperf.com/
- 編寫有利于引擎優(yōu)化的代碼观堂。比如按照 asm.js 規(guī)范編寫的代碼让网,將直接獲得引擎層面的優(yōu)化支持
- 《High Performance Javascript》
優(yōu)化手段有很多,但收益并不相同师痕,像針對(duì) js 引擎的優(yōu)化寂祥,基本只有框架會(huì)去做。有明顯收益的七兜,主要是緩存丸凭、按需加載、減小資源體積腕铸、請(qǐng)求并發(fā)/前置惜犀,可參考淘寶天貓首頁(yè)性能對(duì)賭優(yōu)化回憶錄(鏈接: pan.baidu.com/s/1mgILtDfD… 提取碼: impp),可以說是把這些手段用到了極致狠裹。
有想了解更多的小伙伴可以加Q群鏈接里面看一下虽界,希望能夠?qū)δ銈冇兴鶐椭?/p>