vue項(xiàng)目中一定會(huì)用到的性能優(yōu)化技巧
引言
提起性能優(yōu)化 很多人眼前浮現(xiàn)的面試經(jīng)驗(yàn)是不是歷歷在目呢?反正,性能優(yōu)化在我看來(lái)他永遠(yuǎn)是前端領(lǐng)域的熱度之王。
而本渣最近維護(hù)的項(xiàng)目恰巧在這個(gè)方向下了很大功夫,一些經(jīng)驗(yàn)之談奉上,希望對(duì)大家有些許幫助!
性能優(yōu)化標(biāo)準(zhǔn)
既然說(shuō)性能優(yōu)化,那他總得有一個(gè)公認(rèn)的標(biāo)準(zhǔn),這就是我們很多次聽(tīng)到的Lighthouse
在很多單位,都有著自己的性能監(jiān)控平臺(tái),我們只需要引入相應(yīng)的sdk,那么在平臺(tái)上就能分析出你頁(yè)面的存在的性能問(wèn)題,大家是不是學(xué)的很神奇!
其實(shí)除了苛刻的業(yè)務(wù),需要特殊的定制,大多數(shù)的情況下我們單位的性能優(yōu)化平臺(tái)本質(zhì)上其實(shí)就是利用無(wú)頭瀏覽器(Puppeteer)跑Lighthouse。
理解了我們單位的性能監(jiān)控平臺(tái)的原理之后,我們就能針對(duì)性的做性能優(yōu)化,也就是面向Lighthouse編程
Lighthouse
lighthouse 是 Google Chrome 推出的一款開(kāi)源自動(dòng)化工具,它可以搜集多個(gè)現(xiàn)代網(wǎng)頁(yè)性能指標(biāo),分析 Web 應(yīng)用的性能并生成報(bào)告,為開(kāi)發(fā)人員進(jìn)行性能優(yōu)化的提供了參考方向。
說(shuō)起Lighthouse在現(xiàn)代的谷歌瀏覽器中業(yè)已經(jīng)集成
他可以分析出我們的頁(yè)面性能,通過(guò)幾個(gè)指標(biāo)
Lighthouse 會(huì)衡量以下性能指標(biāo)項(xiàng):
- 首次內(nèi)容繪制(First Contentful Paint)。即瀏覽器首次將任意內(nèi)容(如文字、圖像、canvas 等)繪制到屏幕上的時(shí)間點(diǎn)。
- 可交互時(shí)間(Time to Interactive)。指的是所有的頁(yè)面內(nèi)容都已經(jīng)成功加載,且能夠快速地對(duì)用戶(hù)的操作做出反應(yīng)的時(shí)間點(diǎn)。
- 速度指標(biāo)(Speed Index)。衡量了首屏可見(jiàn)內(nèi)容繪制在屏幕上的速度。在首次加載頁(yè)面的過(guò)程中盡量展現(xiàn)更多的內(nèi)容,往往能給用戶(hù)帶來(lái)更好的體驗(yàn),所以速度指標(biāo)的值約小越好。
- 總阻塞時(shí)間(Total Blocking Time)。指First Contentful Paint 首次內(nèi)容繪制 (FCP)與Time to Interactive 可交互時(shí)間 (TTI)之間的總時(shí)間
- 最大內(nèi)容繪制(Largest Contentful Paint)。度量標(biāo)準(zhǔn)報(bào)告視口內(nèi)可見(jiàn)的最大圖像或文本塊的呈現(xiàn)時(shí)間
- 累積布局偏移(# Cumulative Layout Shift)。衡量的是頁(yè)面整個(gè)生命周期中每次元素發(fā)生的非預(yù)期布局偏移得分的總和。每次可視元素在兩次渲染幀中的起始位置不同時(shí),就說(shuō)是發(fā)生了LS(Layout Shift)。
在一般情況下,據(jù)我的經(jīng)驗(yàn),由于性能監(jiān)控平臺(tái)的和本地平臺(tái)的差異,本地可能要達(dá)到70分,線(xiàn)上才有可能達(dá)到及格的狀態(tài),如果有性能優(yōu)化的需求時(shí),大家酌情處理即可(不過(guò)本人覺(jué)得,及格即可, 畢竟大學(xué)考試有曰:60分萬(wàn)歲,61分浪費(fèi),傳承不能丟,咱們要把更多的時(shí)間,放到更重要的事情上來(lái)!)
通用常規(guī)優(yōu)化手段
lighthouse的的牛x之處就是它能找出你頁(yè)面中的一些常規(guī)的性能瓶頸,并提出優(yōu)化建議,比如:
于是針對(duì)這些優(yōu)化建議,我們需要做一些常規(guī)的優(yōu)化:
- 減少未使用的javascript
- 移出阻塞渲染的資源
- 圖片質(zhì)量壓縮
- 限制使用字體數(shù)量,盡可能少使用變體
- 優(yōu)化關(guān)鍵渲染路徑:只加載當(dāng)前頁(yè)面渲染所需的必要資源,將次要資源放在頁(yè)面渲染完成后加載
通用性能優(yōu)化分析
我們知道lighthouse 中有六個(gè)性能指標(biāo),而在這六個(gè)指標(biāo)中,LCP、 FCP、speed index、 這三個(gè)指數(shù)尤為重要,因?yàn)樵谝话闱闆r下 這個(gè)三個(gè)指標(biāo)會(huì)影響 TTI、TBT、CLS 的分?jǐn)?shù)
所以在我們?cè)趦?yōu)化時(shí), 需要提高LCP、 FCP和speedIndex 的分?jǐn)?shù),經(jīng)過(guò)測(cè)試, 即使是空頁(yè)面也會(huì)有時(shí)間上的損耗, 初始分?jǐn)?shù)基本都是0.8秒
注意: 需要值得大家注意的是,我們當(dāng)前所有測(cè)試全部建立在,移動(dòng)端(之所以用移動(dòng)端,是由于pc 的強(qiáng)大算力,很少有性能瓶頸)的基礎(chǔ)上,并且頁(yè)面上必須有一下內(nèi)容,才能得出分?jǐn)?shù),內(nèi)容必須包括一下的一種或者多種
- 內(nèi)嵌在svg元素內(nèi)的image元素
- video元素(使用封面圖像)
- 通過(guò)url()函數(shù)(而非使用CSS 漸變)加載的帶有背景圖像的元素
- 包含文本節(jié)點(diǎn)或其他行內(nèi)級(jí)文本元素子元素的塊級(jí)元素。
否則就會(huì)有如下錯(cuò)誤
接下來(lái)我們就從LCP、 FCP和speedIndex 這三個(gè)指標(biāo)入手
FCP(First Contentful Paint)
顧名思義就是首次內(nèi)容繪制,也就是頁(yè)面最開(kāi)始繪制內(nèi)容的時(shí)間,但是由于我們現(xiàn)在開(kāi)發(fā)的頁(yè)面都是spa應(yīng)用,所以,框架層面的初始化是一定會(huì)有一定的性能損耗的,以vue-cli 搭建的腳手架為例,當(dāng)我初始化空的腳手架,打包后上傳cdn部署,F(xiàn)CP 就會(huì)從0.8s提上到1.5秒,由此可見(jiàn)vue 的diff 也不是免費(fèi)的他也會(huì)有性能上的損耗
在優(yōu)化頁(yè)面的內(nèi)容之前我們聲明三個(gè)前提
- 提高FCP的時(shí)間其實(shí)就是在優(yōu)化關(guān)鍵渲染路徑
- 如果它是一個(gè)樣式文件(CSS文件),瀏覽器就必須在渲染頁(yè)面之前完全解析它(這就是為什么說(shuō)CSS具有渲染阻礙性)
- 如果它是一個(gè)腳本文件(JavaScript文件),瀏覽器必須: 停止解析,下載腳本,并運(yùn)行它。只有在這之后,它才能繼續(xù)解析,因?yàn)?JavaScript 腳本可以改變頁(yè)面內(nèi)容(特別是HTML)。(這就是為什么說(shuō)JavaScript阻塞解析)
針對(duì)以上的用例測(cè)試,我們發(fā)現(xiàn),無(wú)論我們?cè)趺磧?yōu)化,框架本身的性能損耗是無(wú)法抹除的,我們唯一能做的就是讓框架更早的去執(zhí)行初始化,并且初始化更少的內(nèi)容,可做的優(yōu)化手段如下:
- 所有初始化用不到的js 文件全部走異步加載,也就是加上defer或者asnyc ,并且一些需要走cdn的第三方插件需要放在頁(yè)面底部(因?yàn)榉旁陧敳?,他的解析?huì)阻止html 的解析,從而影響css 等文件的下載,這也是雅虎軍規(guī)的一條)
- js 文件拆包,以vue-cli 為例,一般情況下我們可以通過(guò)cli的配置 splitChunks 做代碼分割,將一些第三方的包走cdn,或者拆包。如果有路由的情況下將路由做拆包處理,保證每個(gè)路由只加載當(dāng)前路由對(duì)應(yīng)的js代碼
- 優(yōu)化文件大小 減少字體包、css文件、以及js文件的大?。ó?dāng)然這些 腳手架默認(rèn)都已經(jīng)做了)
- 優(yōu)化項(xiàng)目結(jié)構(gòu),每個(gè)組件的初始化都是有性能損耗的,在在保證可維護(hù)性的基礎(chǔ)上,盡量減少初始化組件的加載數(shù)量
5、網(wǎng)絡(luò)協(xié)議層面的優(yōu)化,這個(gè)優(yōu)化手段需要服務(wù)端配合純前端已經(jīng)無(wú)法達(dá)到,在現(xiàn)在云服務(wù)器盛行的時(shí)代,自家單位一般都會(huì)默認(rèn)在云服務(wù)器中開(kāi)啟這些優(yōu)化手段,比如開(kāi)啟gzip,使用cdn 等等
其實(shí)說(shuō)來(lái)說(shuō)去,提高FCP 的核心只有理念之后兩個(gè) 減少初始化視圖內(nèi)容和 減少初始化下載資源大小
LCP(Largest Contentful Paint)
顧名思義就是最大內(nèi)容繪制, 何時(shí)報(bào)告LCP,官方是這樣說(shuō)的
為了應(yīng)對(duì)這種潛在的變化,瀏覽器會(huì)在繪制第一幀后立即分發(fā)一個(gè)largest-contentful-paint類(lèi)型的PerformanceEntry,用于識(shí)別最大內(nèi)容元素。但是,在渲染后續(xù)幀之后,瀏覽器會(huì)在最大內(nèi)容元素發(fā)生變化時(shí)分發(fā)另一個(gè)PerformanceEntry。
例如,在一個(gè)帶有文本和首圖的網(wǎng)頁(yè)上,瀏覽器最初可能只渲染文本部分,并在此期間分發(fā)一個(gè)largest-contentful-paint條目,其element屬性通常會(huì)引用一個(gè)<p>或<h2> 。隨后,一旦首圖完成加載,瀏覽器就會(huì)分發(fā)第二個(gè)largest-contentful-paint條目,其element屬性將引用<img> 。
需要注意的是,一個(gè)元素只有在渲染完成并且對(duì)用戶(hù)可見(jiàn)后才能被視為最大內(nèi)容元素。尚未加載的圖像不會(huì)被視為"渲染完成"。 在字體阻塞期使用網(wǎng)頁(yè)字體的文本節(jié)點(diǎn)亦是如此。在這種情況下,較小的元素可能會(huì)被報(bào)告為最大內(nèi)容元素,但一旦更大的元素完成渲染,就會(huì)通過(guò)另一個(gè)PerformanceEntry對(duì)象進(jìn)行報(bào)告。
其實(shí)用大白話(huà)解釋就是,通常情況下,圖片、視頻以及大量文本繪制完成后就會(huì)報(bào)告LCP
理解了這一點(diǎn),的優(yōu)化手段就明確了,盡量減少這些資源的大小就可以了,經(jīng)過(guò)測(cè)試,減少首屏渲染的圖片以及視頻內(nèi)容大小后,整體分?jǐn)?shù)顯著提高,提供一些優(yōu)化方法:
- 本地圖片可以使用在線(xiàn)壓縮工具自己壓縮 推薦tinypng.com
- 接口中附帶圖片,一般情況下單位中都有對(duì)應(yīng)的oss或者cdn傳參配置通過(guò)地址欄傳參方式控制圖片質(zhì)量
- 圖片懶加載
SpeedIndex(速度指數(shù))
Speed Index采用可視頁(yè)面加載的視覺(jué)進(jìn)度,計(jì)算內(nèi)容繪制速度的總分。為此,首先需要能夠計(jì)算在頁(yè)面加載期間,各個(gè)時(shí)間點(diǎn)“完成”了多少部分。在WebPagetest中,通過(guò)捕獲在瀏覽器中加載頁(yè)面的視頻并檢查每個(gè)視頻幀(在啟用視頻捕獲的測(cè)試中,每秒10幀)來(lái)完成的,這個(gè)算法在下面有描述,但現(xiàn)在假設(shè)我們可以為每個(gè)視頻幀分配一個(gè)完整的百分比(在每個(gè)幀下顯示的數(shù)字)
以上是官方解釋的計(jì)算方式,其實(shí)通俗的將,所謂速度指數(shù)就是衡量頁(yè)面內(nèi)容填充的速度
一圖勝千言
經(jīng)過(guò)測(cè)試,跟LCP相同,圖片以及視頻內(nèi)容對(duì)于SpeedIndex的影響巨大,所有優(yōu)化方向,通之前一致,總的來(lái)說(shuō),只要提高LCP 以及FCP 的時(shí)間SpeedIndex 的時(shí)間就會(huì)有顯著提高
不過(guò)需要注意的是,接口的速度也會(huì)影響SpeedIndex的時(shí)間,由于A(yíng)JAX流行的今天,我們大多數(shù)的數(shù)據(jù)都是使用接口拉取。如果接口速度過(guò)慢,他就會(huì)影響你頁(yè)面的初始渲染, 導(dǎo)致性能問(wèn)題,所以,在做性能優(yōu)化的同時(shí),請(qǐng)求后端伙伴協(xié)助,也是性能優(yōu)化的一個(gè)方案
排查性能瓶頸
上述分析,根據(jù)三個(gè)指標(biāo)提供了一些常規(guī)的優(yōu)化手段,那么在這些優(yōu)化手段中,有的你可以立馬排查到,并且優(yōu)化例如:
- 優(yōu)化圖像,優(yōu)化字體大小
- 跟服務(wù)端配合利用瀏覽器緩存機(jī)制.啟用cdn、啟用gzip等
- 減少網(wǎng)絡(luò)協(xié)議過(guò)程中的消耗,減少http 請(qǐng)求、減少dns查詢(xún)、避免重定向
- 優(yōu)化關(guān)鍵渲染路徑,異步加載js等
但是有的優(yōu)化手段我們不容易排查,因?yàn)樗谴蛟诎锩娴?,這個(gè)js 文件包含了很多邏輯怎么辦,這里我有兩個(gè)手段或許能夠幫助排查出性能瓶頸發(fā)生在哪里:
分析包內(nèi)容
在通常情況下,我們無(wú)法判斷的優(yōu)化點(diǎn),都是在打包后,我們無(wú)法分析出,那些東西不是我們?cè)谑灼帘仨毿枰模瑥亩荒茏龀鲠槍?duì)新的優(yōu)化,為了解決當(dāng)前問(wèn)題,各大bundle廠(chǎng)商也都有各自的分析包的方案
以vue-cli 為例
"report": "vue-cli-service build --report"
我們只需要在腳手架中提供以上命令,就能在打包時(shí)生成,整個(gè)包的分析文件
如上圖所示 在打包后就能分析出打包后的js 文件他包含什么組件,如此以來(lái),我們就能知道那些文件是沒(méi)必要同步加載的,或者走cdn的,通過(guò)配置將他單獨(dú)的隔離開(kāi)來(lái),從而找出性能的問(wèn)題
利用chorme devtool 的代碼覆蓋率
如下圖所示,
利用 devtool的代碼覆蓋率檢查就能知道那些js 或者css 文件的代碼沒(méi)有被使用過(guò),結(jié)合包內(nèi)容的分析,我們就能大概的猜出性能的瓶頸在哪里從而做相應(yīng)的特殊處理
針對(duì)vue 的特殊優(yōu)化
以上內(nèi)容都是通用的一些優(yōu)化手段,您在哪都能查到,只是我表達(dá)了一下做這些常規(guī)優(yōu)化的深層原因。能讓您更清楚的了解這些原因之后,在性能瓶頸的時(shí)候能游刃有余,而不是為了面試死記硬背,一到用的時(shí)候就不靈
然后我司是vue啊,咱得上得vue 的手段
圖片懶加載
所謂圖片懶加載,就是頁(yè)面只渲染當(dāng)前可視區(qū)域內(nèi)的圖片,如此一來(lái),減少了其他圖片渲染數(shù)量,能大大提高SpeedIndex和LCP的時(shí)間,從而提高分?jǐn)?shù)
在vue中提起圖片懶加載插件,首推vue-lazyload
使用方式簡(jiǎn)單,功能豐富
虛擬滾動(dòng)
在一含有長(zhǎng)列表頁(yè)面中,你有沒(méi)有發(fā)現(xiàn)你是往下越滑越卡,此時(shí)虛擬滾動(dòng)就排上用場(chǎng)了, 他的基本原理就是只渲染可視區(qū)域內(nèi)的幾條數(shù)據(jù),但是模擬出正?;瑒?dòng)的效果,因?yàn)槊看沃讳秩究墒莿∮騼?nèi)的數(shù)據(jù),在滑動(dòng)的時(shí)候他的性能就會(huì)有飛速提升
在vue中比較好用的插件有兩個(gè)vue-virtual-scroller和vue-virtual-scroll-list
目前我司統(tǒng)一用的vue-virtual-scroll-list 他下拉的時(shí)候到了分頁(yè)的地方能加些loading提示
vue 中的函數(shù)式組件
在vue中我們知道組件的初始化是比較損耗性能的,大家可以去試一下,使用vue 直接渲染一個(gè)文字內(nèi)容,和直接渲染一個(gè)app.vue 組件他的分?jǐn)?shù)是略有不同的。
但是當(dāng)有了函數(shù)式組件,這個(gè)問(wèn)題就迎刃而解了
因?yàn)楹瘮?shù)是組件顧名思義他就是個(gè)函數(shù),說(shuō)白了就是個(gè)render函數(shù),他少了組件初始化的過(guò)程,省去了很多初始化過(guò)程的開(kāi)銷(xiāo)
什么時(shí)候用函數(shù)式組件呢?
當(dāng)你的組件中沒(méi)有業(yè)務(wù)邏輯只展示內(nèi)容時(shí),這時(shí)候函數(shù)式組件就派上用場(chǎng)了
利用v-show 、KeepAlive 復(fù)用dom
我們知道v-show是通過(guò)display 控制dom的展示隱藏,他并不會(huì)刪除dom 而我們?cè)谇袚Qv-show的時(shí)候其實(shí)是減少了diff的對(duì)比,而KeepAlive 則是直接復(fù)用dom,連diff 的過(guò)程都沒(méi)了,并且他們倆的合理使用還不會(huì)影響到初始化渲染。如此一來(lái)減少了js 的執(zhí)行開(kāi)銷(xiāo),但是值得注意的是,他并不能優(yōu)化你初始化的性能,而是操作中的性能
分批渲染組件
在前面我們提到過(guò)SpeedIndex 的漸進(jìn)渲染是提高SpeedIndex的關(guān)鍵,有了這個(gè)前提,我們就可以分批異步渲染組件。先看到內(nèi)容,然后在渲染其他內(nèi)容
舉個(gè)例子:
<template> <div> {{ data1 }} </div> <div v-if="data1"> {{ data2 }} </div> </template> <script> import { ref } from 'vue' export default { setup() { let data1 = ref('') let data2 = ref('') // 假設(shè) 這是從后端取到的數(shù)據(jù) const data = { data1: '這是渲染內(nèi)容1', data2: '這是渲染內(nèi)容2' } data1.value = data.data1 //利用requestAnimationFrame 在空閑的時(shí)候當(dāng)前渲染之后在渲染剩余內(nèi)容 requestIdleCallback(() => { data2.value = data.data2 }) return { data1, data2 } }, } </script>
上述例子比較簡(jiǎn)單可能描述的不太貼切,在這里特此說(shuō)明一下,當(dāng)前方法適用于組件內(nèi)容較多,每次render 時(shí)間過(guò)長(zhǎng),導(dǎo)致白屏?xí)r間過(guò)長(zhǎng),比如,一次拉取用戶(hù)列表,那么分批渲染就非常合適,先展示一部分用戶(hù)信息,最后直到慢慢將所有內(nèi)容渲染完畢。如此對(duì)瀏覽器的SpeedIndex 也非常友好
最后
性能優(yōu)化一直是一個(gè)很火的話(huà)題, 不管從面試以及工作中都非常重要,有了這些優(yōu)化的點(diǎn),你在寫(xiě)代碼或者優(yōu)化老項(xiàng)目時(shí)都能游刃有余,能提前考慮到其中的一些坑,并且規(guī)避。
但是大家需要明白的是,不要為了性能優(yōu)化而性能優(yōu)化,我們?cè)谝虻刂埔?,在不破壞?xiàng)目可維護(hù)性的基礎(chǔ)上去優(yōu)化,千萬(wàn)不要你優(yōu)化個(gè)項(xiàng)目性能是好了,但是大家都看不懂了,這就有點(diǎn)得不償失了,還是那句話(huà),60分萬(wàn)歲61份浪費(fèi),差不多得了,把經(jīng)歷留著去干更重要的事情!
以上就是vue項(xiàng)目中一定會(huì)用到的性能優(yōu)化技巧的詳細(xì)內(nèi)容,更多關(guān)于vue項(xiàng)目性能優(yōu)化技巧的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
vue中使用v-if,v-else來(lái)設(shè)置css樣式的步驟
我們?cè)谑褂胿ue項(xiàng)目開(kāi)發(fā)時(shí),v-if是使用的非常多的,在這里我們談?wù)勅绾问褂胿-i來(lái)綁定修改css樣式,使用的主要是雙向數(shù)據(jù)綁定,即通過(guò)改變他的狀態(tài)來(lái)改變他的樣式,這篇文章主要介紹了vue中如何使用v-if,v-else來(lái)設(shè)置css樣式,需要的朋友可以參考下2023-03-03詳解vue-cli 快速搭建單頁(yè)應(yīng)用之遇到的問(wèn)題及解決辦法
這篇文章主要介紹了詳解vue-cli 快速搭建單頁(yè)應(yīng)用之遇到的問(wèn)題及解決辦法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-03-03el-date-picker設(shè)置日期默認(rèn)值兩種方法(當(dāng)月月初至月末)
這篇文章主要給大家介紹了關(guān)于el-date-picker設(shè)置日期默認(rèn)值(當(dāng)月月初至月末)的相關(guān)資料,文中通過(guò)代碼示例將解決的辦法介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-08-08Vue查詢(xún)數(shù)據(jù)并通過(guò)bootstarp?table渲染數(shù)據(jù)
這篇文章主要為大家介紹了Vue查詢(xún)數(shù)據(jù)并通過(guò)bootstarp?table渲染數(shù)據(jù),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-04-04Vue實(shí)現(xiàn)大屏頁(yè)面的屏幕自適應(yīng)
這篇文章主要為大家詳細(xì)介紹了Vue實(shí)現(xiàn)大屏頁(yè)面的屏幕自適應(yīng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-10-10element-ui表單提交自動(dòng)清空隱藏表單值實(shí)現(xiàn)
這篇文章主要為大家介紹了element-ui表單提交自動(dòng)清空隱藏表單值實(shí)現(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-07-07