一、代碼層面的優(yōu)化
(1)v-if 和 v-show 區(qū)分使用場(chǎng)景
v-if是DOM的銷毀和重建,v-show只是簡(jiǎn)單的控制css的display屬性,v-if適用于不需要頻繁切換條件的場(chǎng)景,v-show則適用于需要頻繁切換條件的場(chǎng)景
(2)computed 和 watch 區(qū)分使用場(chǎng)景
computed是計(jì)算屬性,當(dāng)我們需要進(jìn)行數(shù)值計(jì)算,并且依賴于其它數(shù)據(jù)時(shí),應(yīng)該使用computed,因?yàn)榭梢岳?computed 的緩存特性,避免每次獲取值時(shí),都要重新計(jì)算。
watch更多的是「觀察」的作用,類似于某些數(shù)據(jù)的監(jiān)聽(tīng)回調(diào) ,當(dāng)我們需要在數(shù)據(jù)變化時(shí)執(zhí)行異步或開(kāi)銷較大的操作時(shí),應(yīng)該使用 watch,使用 watch 選項(xiàng)允許我們執(zhí)行異步操作 ( 訪問(wèn)一個(gè) API ),限制我們執(zhí)行該操作的頻率,并在我們得到最終結(jié)果前,設(shè)置中間狀態(tài)。這些都是計(jì)算屬性無(wú)法做到的。
(3)使用keep-alive
根據(jù)業(yè)務(wù)決定那些頁(yè)面使用keep-alive
(4)始終為 v-for 添加 key,并且不要將 index 作為key
id 作為 key 時(shí),僅僅是移動(dòng)了節(jié)點(diǎn),并沒(méi)有觸發(fā) Item 的重新渲染。index 作為 key 時(shí),觸發(fā)了 Item 的重新渲染,可想而知,當(dāng) Item 是一個(gè)復(fù)雜的組件時(shí),必然會(huì)引起性能問(wèn)題。
(5)事件銷毀
Vue組件銷毀時(shí),會(huì)自動(dòng)清理它與其他實(shí)例的連接,解綁它的全部指令及事件監(jiān)聽(tīng)器,但是僅限于組件本身的事件。如果在js內(nèi)使用addEventListener等方式是不會(huì)自動(dòng)銷毀的,我們需要在組件銷毀時(shí)手動(dòng)移除這些事件的監(jiān)聽(tīng)比如removeEventListener,以免造成內(nèi)存泄漏。
(6)css寫在頁(yè)面頭部,js腳本寫在頁(yè)面底部或異步加載
css盡量寫在head中,因?yàn)閏ss加載會(huì)阻塞頁(yè)面的加載,這是有好處的,這避免了頁(yè)面加載時(shí)會(huì)出現(xiàn)css沒(méi)加載完而導(dǎo)致的出現(xiàn)頁(yè)面一閃的情況,同時(shí),css的加載是會(huì)阻塞JS的執(zhí)行,但不阻塞引入JS的加載。
js盡量寫在HTML文本的底部,因?yàn)閖s的引入會(huì)阻塞頁(yè)面的渲染,也依賴于DOM節(jié)點(diǎn)。所以,應(yīng)該先讓HTML,CSS先行加載,最后加載JS。
JS代碼異步加載
- async:加載完成后立即執(zhí)行,所以會(huì)在dom加載完之前執(zhí)行,在async執(zhí)行完之后,html再繼續(xù)解析,如果是多個(gè)腳本,該方法不能保證腳本按順序執(zhí)行。
-
defer:加載完成等到HTML解析完之后才會(huì)執(zhí)行,如果是多個(gè)腳本,按照加載的順序依次執(zhí)行。
其中藍(lán)色線表示網(wǎng)絡(luò)讀取,紅色線表示執(zhí)行時(shí)間,這兩個(gè)都是針對(duì)腳本的;綠色線表示HTML解析。
使用場(chǎng)景
如果有多個(gè)腳本,它們之間的依賴關(guān)系很強(qiáng)使用defer,依賴關(guān)系不強(qiáng)使用async或defer。
(7)CSS sprite(圖像精靈)
它是將大大小小的圖片合并為一張大圖,再使用圖片定位來(lái)顯示對(duì)應(yīng)的圖片,這樣可以減少http請(qǐng)求個(gè)數(shù),提高頁(yè)面加載速度。但也有個(gè)缺點(diǎn)就是既然是合成一張大圖,那么很多小圖片就依賴這一張圖片,如果這個(gè)圖片沒(méi)有加載出來(lái)那么整個(gè)頁(yè)面基本上就缺失了
(8)圖片懶加載
對(duì)于圖片過(guò)多的頁(yè)面,為了加速頁(yè)面加載速度,所以很多時(shí)候我們需要將頁(yè)面內(nèi)未出現(xiàn)的可視區(qū)域內(nèi)的圖片先不做加載,等到滾動(dòng)到可視區(qū)域后再去加載。這樣對(duì)于頁(yè)面加載性能上會(huì)有很大的提升,也提高了用戶體驗(yàn)。我們?cè)陧?xiàng)目中使用Vue的vue-lazyload插件:
(1)安裝插件
npm install vue-lazyload --save-dev
(2)在入口文件main.js中引入并使用
import VueLazyload from 'vue-lazyload'
Vue.use(VueLazyload)
(3)在vue文件中將img標(biāo)簽的src屬性直接改為v-lazy,從而將圖片顯示方式更改為懶加載顯示
<img v-lazy="/static/img/1.png">
(9)路由懶加載
Vue 是單頁(yè)面應(yīng)用,可能會(huì)有很多的路由引入 ,這樣使用 webpcak 打包后的文件很大,當(dāng)進(jìn)入首頁(yè)時(shí),加載的資源過(guò)多,頁(yè)面會(huì)出現(xiàn)白屏的情況,不利于用戶體驗(yàn)。如果我們能把不同路由對(duì)應(yīng)的組件分割成不同的代碼塊,然后當(dāng)路由被訪問(wèn)的時(shí)候才加載對(duì)應(yīng)的組件,這樣會(huì)大大提高首屏顯示的速度,但是可能其他的頁(yè)面的速度就會(huì)降下來(lái)。
路由懶加載:
const Foo = () => import('./Foo.vue')
const router = new VueRouter({
routes: [
{ path: '/foo', component: Foo }
]
})
(10)優(yōu)化無(wú)限列表性能
如果你的應(yīng)用存在非常長(zhǎng)或者無(wú)限滾動(dòng)的列表,那么需要采用 窗口化 的技術(shù)來(lái)優(yōu)化性能,只需要渲染少部分區(qū)域的內(nèi)容,減少重新渲染組件和創(chuàng)建 dom 節(jié)點(diǎn)的時(shí)間。 你可以參考以下開(kāi)源項(xiàng)目 vue-virtual-scroll-list 和 vue-virtual-scroller 來(lái)優(yōu)化這種無(wú)限列表的場(chǎng)景。
(11)第三方插件按需引入
我們?cè)陧?xiàng)目中經(jīng)常需要引入第三方插件,如果我們直接引入 整個(gè)插件,會(huì)導(dǎo)致 項(xiàng)目體積太大,我們可以借助babel-plugin-component,然后只引入需要的組件,以達(dá)到減小項(xiàng)目體積的目的,以下是vue項(xiàng)目引入element-ui組件庫(kù)為例:
- 首先安裝babel-plugin-component
npm install babel-plugin-component -D
- 第二步是將.babelrc修改為:
{
"plugins": [
[
"component",
{
"libraryName": "element-ui",
"styleLibraryName": "theme-chalk"
}
]
]
}
- 第三步是在main.js中引入部分組件:
import Vue from 'vue';
import { Button, Select } from 'element-ui';
Vue.use(Button)
Vue.use(Select)
跟我們之前按需引入部分組件不同之處在于,我們是整體引入css樣式import element-ui/lib/theme-chalk/index.css,現(xiàn)在這種方式不僅按需引入部分組件還按需引入部分樣式
(12)減少ES6轉(zhuǎn)為ES5的冗余代碼
Babel 插件會(huì)在將 ES6 代碼轉(zhuǎn)換成 ES5 代碼時(shí)會(huì)注入一些輔助函數(shù),例如下面的 ES6 代碼:
class HelloWebpack extends Component{...}
這段代碼再被轉(zhuǎn)換成能正常運(yùn)行的 ES5 代碼時(shí)需要以下兩個(gè)輔助函數(shù):
babel-runtime/helpers/createClass // 用于實(shí)現(xiàn) class 語(yǔ)法
babel-runtime/helpers/inherits // 用于實(shí)現(xiàn) extends 語(yǔ)法
在默認(rèn)情況下, Babel 會(huì)在每個(gè)輸出文件中內(nèi)嵌這些依賴的輔助函數(shù)代碼,如果多個(gè)源代碼文件都依賴這些輔助函數(shù),那么這些輔助函數(shù)的代碼將會(huì)出現(xiàn)很多次,造成代碼冗余。為了不讓這些輔助函數(shù)的代碼重復(fù)出現(xiàn),可以在依賴它們時(shí)通過(guò) require('babel-runtime/helpers/createClass') 的方式導(dǎo)入,這樣就能做到只讓它們出現(xiàn)一次。@babel/plugin-transform-runtime 插件就是用來(lái)實(shí)現(xiàn)這個(gè)作用的,將相關(guān)輔助函數(shù)進(jìn)行替換成導(dǎo)入語(yǔ)句,從而減小 babel 編譯出來(lái)的代碼的文件大小。
(1)首先,安裝 @babel/plugin-transform-runtime
npm install @babel/plugin-transform-runtime --D
(2)然后,修改 .babelrc 配置文件為:
"plugins": ["@babel/plugin-transform-runtime"]
二、基礎(chǔ)的 Web 技術(shù)優(yōu)化
(1)開(kāi)啟 gzip 壓縮
在打開(kāi)網(wǎng)頁(yè)時(shí),會(huì)首先加載各種資源,js、css、圖片等等,這些文件一般比較大,打開(kāi)網(wǎng)頁(yè)也比較慢,用戶體驗(yàn)不好,所以提出gzip壓縮,可以將文件縮小2-3倍,文件越小頁(yè)面打開(kāi)速度越快,需要配置nginx和webpack,在nginx中
// nginx開(kāi)啟gzip服務(wù)
gzip on;
gzip_disable "msie6";
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_buffers 16 8k;
gzip_http_version 1.1;
// 需要開(kāi)啟gzip的格式
gzip_types text/plain text/css application/json application/x-javascript text/xml
application/xml application/xml+rss text/javascript image/jpeg image/gif image/png image/jpg;
配置完成后,需要重啟一下nginx即可。
接下來(lái)我們就要在前端vue項(xiàng)目中進(jìn)行g(shù)zip相關(guān)的配置了,首先我們需要安裝一個(gè)插件:
npm i -D compression-webpack-plugin
安裝完成后,在我們項(xiàng)目的 vue.config.js 中,引入該插件并配置一下:
const CompressionPlugin = require("compression-webpack-plugin");
module.export = {
configureWebpack: () => {
if (process.env.NODE_ENV === 'production') {
return {
plugins: [
new CompressionPlugin({
test: /\.js$|\.html$|\.css$|\.jpg$|\.jpeg$|\.png/, // 需要壓縮的文件類型
threshold: 10240, // 歸檔需要進(jìn)行壓縮的文件大小最小值,我這個(gè)是10K以上的進(jìn)行壓縮
deleteOriginalAssets: false // 是否刪除原文件
})
]
}
}
}
}
配置完成后,對(duì)項(xiàng)目進(jìn)行 npm run build 打包之后,你可以在dist文件夾下看到相應(yīng)的.gzip的文件,這就是進(jìn)行壓縮后生成的,這時(shí)我們?cè)陂_(kāi)發(fā)者工具中的network中查看我們的js或者其他文件的請(qǐng)求:
注意:webpack4+才會(huì)顯示chunk開(kāi)頭的文件
Request Headers中會(huì)顯示Accept-Encoding: gzip,Response Headers中會(huì)顯示Content-Encoding: gzip這樣就表示配置成功
(2)使用CDN
大型Web應(yīng)用對(duì)速度的追求并沒(méi)有止步于僅僅利用瀏覽器緩存,因?yàn)闉g覽器緩存始終只是為了提升二次訪問(wèn)的速度,對(duì)于首次訪問(wèn)的加速,我們需要從網(wǎng)絡(luò)層面進(jìn)行優(yōu)化,最常見(jiàn)的手段就是CDN(Content Delivery Network,內(nèi)容分發(fā)網(wǎng)絡(luò))加速。通過(guò)將靜態(tài)資源(例如js、css、圖片)緩存到離用戶很近的相同網(wǎng)絡(luò)運(yùn)營(yíng)商的CDN節(jié)點(diǎn)上,不但能提升用戶的訪問(wèn)速度,還能節(jié)省服務(wù)器的帶寬消耗,降低負(fù)載。
CDN是如何做到加速的呢?
其實(shí)這是CDN服務(wù)商在全國(guó)各個(gè)省份部署計(jì)算節(jié)點(diǎn),CDN將網(wǎng)站的內(nèi)容緩存在各個(gè)節(jié)點(diǎn),不同地區(qū)的用戶就會(huì)訪問(wèn)到離自己最近的相同網(wǎng)絡(luò)線路上的CDN節(jié)點(diǎn),當(dāng)請(qǐng)求達(dá)到CDN節(jié)點(diǎn)后,節(jié)點(diǎn)會(huì)判斷自己的內(nèi)容緩存是否有效,如果有效,則立即響應(yīng)緩存內(nèi)容給用戶,從而加快響應(yīng)速度。如果無(wú)效,它會(huì)根據(jù)服務(wù)配置去我們的內(nèi)容源服務(wù)器獲取最新的資源響應(yīng)給用戶,并將內(nèi)容緩存下來(lái)以便響應(yīng)給后續(xù)訪問(wèn)的用戶。因此,一個(gè)地區(qū)只要有一個(gè)用戶先加載資源,在CDN中建立了 緩存 ,該地區(qū)的其他用戶都會(huì)因此受益。
(3)預(yù)解析DNS
資源預(yù)加載是另一個(gè)性能優(yōu)化技術(shù),我們可以使用該技術(shù)來(lái)預(yù)先告知瀏覽器某些資源可能在將來(lái)會(huì)被使用到。通過(guò)DNS預(yù)解析來(lái)告訴瀏覽器未來(lái)我們可能從某個(gè)特定的URL獲取資源,當(dāng)瀏覽器真正使用到該域中的某個(gè)資源時(shí)就可以盡快地完成DNS解析。例如,我們將來(lái)可從example.com獲取圖片或音頻資源,那么可以在文檔頂部的標(biāo)簽中加入以下內(nèi)容:
<link rel="dns-prefetch" >
當(dāng)我們從該URL請(qǐng)求一個(gè)資源時(shí),就不再需要等待DNS的解析過(guò)程。該技術(shù)對(duì)使用第三方資源特別有用。通過(guò)簡(jiǎn)單的一行代碼就可以告知那些兼容的瀏覽器進(jìn)行DNS預(yù)解析,這意味著當(dāng)瀏覽器真正請(qǐng)求該域中的某個(gè)資源時(shí),DNS的解析就已經(jīng)完成了,從而節(jié)省了寶貴的時(shí)間。另外需要注意的是瀏覽器會(huì)對(duì)a標(biāo)簽的href自動(dòng)啟用預(yù)解析,所以a標(biāo)簽包含的域名不需要在head中手動(dòng)設(shè)置link。但是在HTTPS下不起作用,需要meta來(lái)強(qiáng)制開(kāi)啟,這個(gè)限制的原因是防止竊聽(tīng)者根據(jù)DNS預(yù)解析推斷顯示在HTTPS頁(yè)面中超鏈接的主機(jī)名。下面這句作用是強(qiáng)制打開(kāi)a標(biāo)簽的域名解析:
<meta http-equiv="x-dns-prefetch-control" content="on">
(4)利用前端緩存
http://www.lxweimin.com/p/cd3e7498aadc
Webpack層面優(yōu)化
http://www.lxweimin.com/p/f607114cf974