作者:NewName
最近看了一篇前端性能優(yōu)化的文章,之前也沒搞過性能優(yōu)化独郎,就學習了一下淹真。要想搞性能優(yōu)化吮成,得知道都有哪些和性能相關的指標,得知道有什么工具可以量化地評估網(wǎng)站的性能表現(xiàn)凭迹,還得知道怎么進行優(yōu)化婴削、優(yōu)化的思路都有啥。學了一波即碗,決定用Lighthouse這款性能測試工具來評估一下自己開發(fā)的網(wǎng)站的性能,優(yōu)化前得分56,優(yōu)化后得分96,怎么做的呢虫溜?閱讀本文一起學習吧~
1. Lighthouse的使用
Lighthouse 是由Google 開發(fā)并開源的Web 性能測試工具,通過監(jiān)控和檢測網(wǎng)站應用的各方面性能表現(xiàn)初橘,為開發(fā)這提供優(yōu)化用戶體驗和網(wǎng)站性能提供指導建議。
下面介紹兩種使用Lighthouse的方式:通過Chrome插件使用和通過Node CLI使用充岛。
1.1 通過Chrome插件使用
首先現(xiàn)在Lighthouse插件(Lighthouse谷歌瀏覽器插件下載地址:https://chrome.google.com/webstore/detail/lighthouse/blipmdconlkpinefehnmjammfjpmpbjk/related保檐。
然后打開Chrome開發(fā)者工具,點擊右上角的【三個點】崔梗,點擊【更多工具】夜只,再點擊【性能監(jiān)視器】:
然后點擊【Lighthouse】選項卡,點擊【分析網(wǎng)頁加載情況】按鈕:
如下為正在夾斷網(wǎng)頁得分:
幾秒后蒜魄,Lighthouse性能分析報錯生成:
可見性能分數(shù)比較低扔亥,具體指標得分如下:
點擊【展開視圖】可以了解每一指標的含義场躯,可以點擊連接了解每一指標的詳情以及具體優(yōu)化策略:
再往下可以查看優(yōu)化建議:
再往下可以看診斷結果:
1.2 通過Node CLI使用
目前Lighthouse已經(jīng)發(fā)布了npm包,可以在項目中集成:npm i lighthouse
如下為腳本代碼:
const run = async () => {
const browser = await puppeteer.launch({
headless: "new",
args: ["--no-sandbox", "--disable-setuid-sandbox"],
});
const page = await browser.newPage();
const url = "你的網(wǎng)頁url";
await page.goto(url);
const { port } = new URL(browser.wsEndpoint());
const { report } = await lighthouse(url, {
port,
output: "html",
});
await writeFile("report.html", report);
await browser.close();
};
run();
運行腳本即可得到Lighthouse生成的分析報告:
分析報告和瀏覽器插件方式得到在內(nèi)容上是的一樣旅挤,只不過是英文的形式踢关。后續(xù)可以利用在此基礎上進行改善和豐富,可以優(yōu)化前端工程的部署流程谦铃。
有了性能分析報告耘成,我們可以根據(jù)各性能指標得分,優(yōu)化建議和診斷結果對項目進行優(yōu)化驹闰,下面具體學習一下這些性能優(yōu)化指標。
2. 性能優(yōu)化的指標
2.1 FCP ( First Contentful Paint)首次內(nèi)容繪制
2.1.1 定義
首次內(nèi)容繪制時間撒会,測量頁面從開始加載到頁面內(nèi)容的任何部分在屏幕上完成渲染的時間嘹朗。
2.1.2 對定義的理解
所述頁面內(nèi)容必須是文本、圖片(包含背景圖)诵肛,非白色的canvas或SVG屹培。
這是用戶第一次看到頁面的內(nèi)容,注意是部分內(nèi)容怔檩,并非所有內(nèi)容褪秀。
如下圖所示,F(xiàn)CP 發(fā)生在第二幀薛训,因為那是首批文本和圖像元素在屏幕上完成渲染的時間點:
如上圖所示媒吗,雖然部分內(nèi)容已完成渲染,但并非所有內(nèi)容都已經(jīng)完成渲染乙埃。這是首次內(nèi)容繪制時間 (FCP) 與*最大內(nèi)容繪制時間 (LCP闸英,Largest Contentful Paint)之間的重要區(qū)別。
2.1.3 評價標準
FCP時間在0-1.8秒介袜, 表示良好甫何,顏色為綠色,F(xiàn)CP評分將在75~100分遇伞;
FCP時間在1.9-3.0秒辙喂, 表示需要改進,顏色為橙色鸠珠,F(xiàn)CP評分將在50~74分巍耗;
FCP時間在3.1秒以上, 表示較差進跳芳,顏色為紅色芍锦,F(xiàn)CP評分將在0~49分。
2.1.4 縮短FCP時間的方法
指導方案可參照:如何改進 FCP [1]飞盆,本文如何做的見下文娄琉。
2.1.5 注意事項
此指標對于沒有使用ssr技術的web項目意義并不大次乓,因為第一繪制發(fā)生的時間通常JS還沒加載完畢。
2.2 LCP(Largest Contentful Pain)最大內(nèi)容繪制
2.2.1 定義
最大內(nèi)容繪制時間孽水,根據(jù)頁面首次開始加載的時間點來計算可視區(qū)域內(nèi)可見的最大圖像或者文本塊完成渲染的相對時間票腰。
2.2.2 對定義的理解
LCP要考慮的元素包括:img元素以及內(nèi)嵌在svg元素內(nèi)的img元素,video元素女气,通過url()加載的背景圖像元素杏慰,包含文本節(jié)點或者其他內(nèi)聯(lián)級文本元素的塊級元素。
如下圖所示炼鞠,最大元素隨內(nèi)容加載而變化缘滥,隨著新內(nèi)容被添加進 DOM,并因此使最大元素發(fā)生了改變:
2.2.3 評價標準
LCP時間在0-2.5秒谒主, 表示良好朝扼,顏色為綠色;
LCP時間在2.6-4.0秒霎肯, 表示需要改進擎颖,顏色為橙色;
LCP時間在4.1秒以上观游, 表示較差進搂捧,顏色為紅色。
2.2.4 縮短LCP時間的方法
指導方案可參考:如何改進 LCP[2]懂缕,本文如何做的見下文允跑。
2.2.5 注意事項
在某些情況下,頁面上最重要的元素(或多個元素)并不是最大元素提佣,而開發(fā)者可能更有興趣測量前者的渲染時間(使用元素計時API[3])吮蛹。
2.3 TBT (Total Blocking Time)總阻塞時間
2.3.1 定義
總阻塞時間 (TBT) 指標測量First Contentful Paint 首次內(nèi)容繪制 (FCP)與Time to Interactive 可交互時間 (TTI)之間的總時間。
2.3.2 對定義的理解
由定義可知:TBT涉及到了FCP和TTI這兩個概念拌屏, 對于FCP上文已經(jīng)介紹過潮针,這里補充一下TTI(可交互時間的定義):TTI 指標測量頁面從開始加載到主要子資源完成渲染,并能夠快速倚喂、可靠地響應用戶輸入所需的時間每篷。
2.3.3 評價標準
評價標準參加下表:
TBT得分標準[4]
為了提供良好的用戶體驗,網(wǎng)站在普通移動硬件上進行測試時端圈,應當努力使TBT控制在300毫秒以內(nèi)焦读。
2.3.4 縮短TBT的方法
指導方案可參考:如何改進TBT[5],本文如何做的見下文舱权。
2.4 CLS(Cumulative Layout Shift)累積布局偏移
2.4.1 定義
CLS 測量整個頁面生命周期內(nèi)發(fā)生的所有意外布局偏移中最大一連串的布局偏移分數(shù)矗晃。
2.4.2 對定義的理解
累積布局偏移 (CLS) 是測量視覺穩(wěn)定性的一個以用戶為中心的重要指標,因為該項指標有助于量化用戶經(jīng)歷意外布局偏移的頻率宴倍,較低的 CLS 有助于確保一個頁面是令人愉悅的张症。
2.4.3 評價標準
2.4.4 縮短CLS的方法
指導方案可參照:如何改進CLS[6]仓技,本文不涉及。
2.5 SI(Speed Index)速度指標
2.5.1 定義
SI是一個表示頁面可視區(qū)域中內(nèi)容的填充速度的指標俗他。
2.5.2 對定義的理解
該指標捕獲的是頁面出現(xiàn)像素點的時間脖捻。
2.5.3 評價標準
評價標準參加下表:
2.5.5 縮短SI的方法
指導方案可參照:如何改進SI[7],本文如何做的見下文兆衅。
3. 具體的性能優(yōu)化的方法
文檔快速加載總結了一些提升網(wǎng)站性能的技術地沮,列出一下常用的方法:
1.消除阻塞渲染的資源: 例如對于引入三方的script標簽加上async或者defer。
2.縮小CSS羡亩、移除未使用的CSS: 例如使用壓縮器壓縮CSS摩疑。
3.預連接到所需要的資源:例如使用<link rel="preconnect">通知瀏覽器,頁面打算與另一個源建立連接夕春,而且希望該過程盡快開始未荒。
4.減少服務器的響應時間:例如使用HTTP2。
5.使用緩存:例如使用HTTP緩存及志。
6.優(yōu)化圖片:例如壓縮圖片,使用CDN, 延遲加載等寨腔。
7.刪除未使用代碼:例如刪除未使用的庫速侈,刪除不需要的庫,刪除無用代碼迫卢,按需引入組件庫倚搬。
8.減少JS負載:例如動態(tài)導入和代碼拆分。
下面結合筆者的項目介紹一下筆者使用的方法:
3.1 使用vite-compression-plugin
可以使用 vite-compression-plugin[8] 來對代碼進行gizp壓縮乾蛤,使用方法如下:
vite.config.ts:
import viteCompression from 'vite-plugin-compression'
export default defineConfig({
plugins:[
viteCompression({
ext: ".gz",
algorithm: "gzip",
deleteOriginFile: false
})
]
})
關于插件的具體配置可以查看插件的文檔每界,選擇合適的壓縮算法。
3.2 開啟ngnix的gizp壓縮
筆者的前端項目下有一個.devops目錄家卖,下面有一個ngnix.conf文件可以單獨配置此前端工程的ngnix:
配置方法為在server下面增加如下配置:
server {
gzip on;
gzip_buffers 32 4K;
gzip_comp_level 6;
gzip_min_length 100;
gzip_types application/javascript text/plain text/css text/xml application/json application/xml application/xml+rss;
gzip_vary on;
listen 80;
location / {
# 此處省略location相關配置
}
}
具體配置項含義以及取值眨层,可以查詢相關文檔。
3.3 按需自動引入element-plus
筆者項目原來是完整引入element-plus的, main.ts文件內(nèi)容:
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import App from './App.vue'
const app = createApp(App)
app.use(ElementPlus)
app.mount('#app')
這樣會導致首頁加載時被打包后的和element-plus相關的全部js和css資源被引入上荡,但是按需引入時則不會一次性引入全部的css和js趴樱。
按需引入element-plus的方法為:
第一步:安裝unplugin-auto-import和unplugin-vue-components:pnpm install unplugin-auto-import unplugin-vue-components。
第二步:vite.config.ts插件配置:
import AutoImport from "unplugin-auto-import/vite";
import Components from "unplugin-vue-components/vite";
import { ElementPlusResolver } from "unplugin-vue-components/resolvers";
export default defineConfig({
plugins:[
AutoImport({
resolvers: [ElementPlusResolver()]
}),
Components({
resolvers: [ElementPlusResolver()]
}),
]
})
第三步:特殊插件的處理酪捡。對于對于命令式方式使用的組件叁征,例如ElNotification, 如果不單獨引入,則會導致其樣式失效逛薇,所以需要對項目中使用到的這類組件單獨全局引入一下就OK啦:
import { ElInput, ElSelect, ElDatePicker, ElTimePicker } from "element-plus";
app.use(ElInput).use(ElSelect).use(ElDatePicker).use(ElTimePicker).use(directives).use(router).use(pinia).mount("#app");
3.4 修改百度地圖的引入方式
原來的引入方式是在html文件中增加script標簽:
<!DOCTYPE html>
<html lang="en">
<body >
<div id="app">
<script type="module" src="/src/main.ts"></script>
<script charset="utf-8" src="https://api.map.baidu.com/api?v=1.0&&type=webgl&ak=***"></script>
</body>
</html>
原來的使用方法如下:
const BMapGL: any = (window as any).BMapGL;
const map = new BMapGL.Map("container");
改成使用時異步引用:
const LoadBaiduMapScript = () => {
//console.log("初始化百度地圖腳本...");
const AK = "***";
const BMap_URL = "https://api.map.baidu.com/api?v=1.0&&type=webgl&ak=" + AK + "&s=1&callback=onBMapCallback";
return new Promise(resolve => {
// 如果已加載直接返回
if (typeof (window as any).BMapGL !== "undefined") {
resolve((window as any).BMapGL);
return true;
}
// 百度地圖異步加載回調(diào)處理
(window as any).onBMapCallback = () => {
console.log("百度地圖腳本初始化成功...");
BMapGL = (window as any).BMapGL;
resolve((window as any).BMapGL);
};
// 插入script腳本
let scriptNode = document.createElement("script");
scriptNode.setAttribute("type", "text/javascript");
scriptNode.setAttribute("src", BMap_URL);
document.body.appendChild(scriptNode);
});
};
3.5 對圖片進行壓縮
這里推薦一個好用的壓縮工具捺疼,熊貓壓縮——tinypng 。
用它把UI給的切圖永罚、背景圖等壓縮一下啤呼,那必然也起到一定的作用卧秘。
筆者就通過如上五種優(yōu)化方法對項目優(yōu)化了一下,性能得分就得到了很大的改觀媳友,是不是覺得性能優(yōu)化也不難斯议,哈哈哈~
參考資料
[1]如何改進 FCP : https://web.dev/fcp/#
%E5%A6%82%E4%BD%95%E6%94%B9%E8%BF%9B-fcp[2]如何改進 LCP: https://web.dev/lcp/#
%E5%A6%82%E4%BD%95%E6%94%B9%E8%BF%9B-lcp[3]使用元素計時API:
https://wicg.github.io/element-timing/[5]如何改進TBT: https://web.dev/tbt/#
%E5%A6%82%E4%BD%95%E6%94%B9%E8%BF%9B-tbt[6]如何改進CLS: https://web.dev/cls/#
%E5%A6%82%E4%BD%95%E6%94%B9%E8%BF%9B-cls[8]vite-compression-plugin: https://github.com/nonzzz/vite-plugin-compression