前端性能優(yōu)化

一、代碼層面的優(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-listvue-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

性能優(yōu)化圖

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,316評(píng)論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,481評(píng)論 3 415
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 176,241評(píng)論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 62,939評(píng)論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,697評(píng)論 6 409
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 55,182評(píng)論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,247評(píng)論 3 441
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 42,406評(píng)論 0 288
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,933評(píng)論 1 334
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,772評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,973評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,516評(píng)論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,209評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 34,638評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 35,866評(píng)論 1 285
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,644評(píng)論 3 391
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,953評(píng)論 2 373

推薦閱讀更多精彩內(nèi)容