簡介
這是在公司對專案最佳化的一次記錄,過程中並沒有使用什麼高大上的技術,因為造成問題的原因也並不複雜,大部分原因是對vue框架不夠理解造成沒有合理使用。
起因
某天早上領導估計看我閒來無事於是給了我個任務,專案有個模組是以前的同事寫的,同事寫前端的時間不長,目前功能已經完成了,但是開啟頁面的時候很慢,所以想讓我去嘗試最佳化一下。
發現問題
雖然這個模組不是我做的,而且這個專案我也還不熟悉,不然既然接到任務了就試試吧,想要對其進行最佳化,那麼就得先了解該模組的具體情況,這樣才能對症下藥,拿出合理的方案。
頁面是用於展示視覺化報表,頁面有七八個報表,還有一些按鈕用於切換報表,除此之外沒啥了,內容看起來並不複雜,不過開啟頁面到報表有響應大概就花了五六秒,報表完全展示需要差不多一分鐘左右,爲了防止這是偶然事件,我多試了好幾遍,結果大差不差,這個速度可以說相當慢了。
考慮到其他頁面都是正常的,唯獨這個頁面慢,因此先不考慮整個專案的效能問題,而是這個頁面有問題,優先想到了是頁面的渲染以及網路請求的問題。先開啟頁面除錯臺,看是不是DOM樹太多節點了,導致渲染出現了問題。
果然發現了問題,頁面用到了iframe,每個報表都是iframe嵌入了一個頁面,再看了下網路請求,更是倒吸一口涼氣,這個頁面進來時傳送了差不多4500個請求,難怪效能高這麼差了。
下面是請求的圖片:
雖說用到了iframe,但是也不至於會發送那麼多請求啊,帶著這個疑問去去看了下程式碼,發現程式碼確實有問題,程式碼大概是這樣的,下面程式碼只是一個示例,是用來體現問題出現在了哪裏,因此省略了一部分,不用糾結程式碼寫得怎麼樣:
<template> <div> <el-radio-group v-model="radio" size="large"> <el-radio-button label="1" value="1" /> <el-radio-button label="2" value="2" /> </el-radio-group> <div v-for="list in dataList" :key="list.type" v-show="item.type === 'radio'"> <div v-for="item in list" :key="list.id"> <iframe :scr="item.url" /> </div> </div> </div> </template> <script> export default { data() { return { radio: '1', dataList: [ { type: '1', urlList: [ { url: "xxxxxxxxxxxxxxxxxxxxx", id: '1' }, { url: "xxxxxxxxxxxxxxxxxxxxx", id: '2' }, { url: "xxxxxxxxxxxxxxxxxxxxx", id: '3' }, ......... // 還有資料省略 ] }, { type: '2', urlList: [ { url: "xxxxxxxxxxxxxxxxxxxxx", id: '4' }, { url: "xxxxxxxxxxxxxxxxxxxxx", id: '5' }, { url: "xxxxxxxxxxxxxxxxxxxxx", id: '6' }, ........ // 還有資料省略 ] }, .......... // 還有資料省略 ] } } } </script>
上面示例的程式碼,問題就在使用了v-show來隱藏或展示需要想要的檢視,v-show這個指令只是在DOM節點中加上display: none; 讓節點隱藏不渲染,但是節點還是會掛載在DOM樹中。
也正是因為這樣,大概有五十多個iframe節點都掛在了DOM上,只是沒有渲染出來,但是它們都發送了請求,因此剛剛進入頁面的時候是請求了五十多個iframe頁面的請求。
這導致了初始開啟頁面時會發送大量的請求,同時間大量的請求搶佔了瀏覽器的資源,導致了頁面響應慢。
解決問題
既然已經發現了主要問題是因為初始進入頁面時請求了太多資源導致的,那麼優先想到的就是按需載入的方案,既是隻載入頁面需要的資料,不載入多餘的資料,程式碼大致如下。
<template> <div> <el-radio-group v-model="radio" size="large"> <el-radio-button label="1" value="1" /> <el-radio-button label="2" value="2" /> </el-radio-group> <div v-for="item in list" :key="item.id"> <iframe :scr="item.url" /> </div> </div> </template> <script> export default { data() { return { radio: '1', dataList: [...// 省略] } }, computed: { list:() => { const target = list.find(item => item.type === this.radio) return target.urlList } } } </script>
修改的並不多,只是使用了vue的計算屬性computed,每次切換按鈕,computed中的依賴this.radio就會變化進行重新計算,得到需要渲染的資料。
使用了按需載入後,每次進入頁面時傳送的請求明顯變少了很多,頁面的速度也相應提升了很多,頁面在一兩秒內就會有響應反饋,後續頁面報表陸續載入完成,最終在六七秒時候全部載入完成。
雖然效能表現不算多優秀,不過相比沒有最佳化前五六秒纔有感知,現在一兩秒就能給使用者感知反饋已經不錯了,畢竟這個頁面使用到了這麼多個iframe。
前期因為專案趕時間,所以使用了iframe,不過後期放棄直接用iframe的方案,自己寫頁面。
總結
這次的最佳化其實並不難,因為這次的場景比較極端,因此問題比較容易發現,解決問題的關鍵就是要先發現問題,這樣才能對症下藥,拿出合理的方案。
這次造成效能問題的主要問題是使用到了iframe嵌入頁面和對v-show不合理的應用, 一次性發送過多網路請求導致效能慢,從這可以看出網路對效能的影響是非常大的,效能最佳化方面網路是一個重頭,像常見的最佳化方案比如說精靈圖、使用字型圖示、懶載入、按需載入、使用快取、減小打包產物體積、使用CDN等方案都是爲了最佳化網路。
iframe雖然方便,但是的缺點還是比較多的,每個iframe都會單獨載入資源,會使網路請求增多,能不用就不用。