iT邦幫忙

2021 iThome 鐵人賽

DAY 20
1
Modern Web

[ 重構倒數30天,你的網站不Vue白不Vue ] 系列 第 20

[重構倒數第11天] - 如何在 Vue 中寫出高效能的網頁渲染方式 ?

  • 分享至 

  • xImage
  •  

前言

該系列是為了讓看過Vue官方文件或學過Vue但是卻不知道怎麼下手去重構現在有的網站而去規畫的系列文章,在這邊整理了許多我自己使用Vue重構很多網站的經驗分享給讀者們。

我們在開發網頁的時候都希望我們的網頁不管是在第一次進來的時候快速的將畫面給渲染出來,又或是當我們在操作 ui 的時候,畫面上面更新流暢且不會卡頓,今天我們就要來談一談幾種提升頁面渲染效能的方式,正所謂積少成多,當這些小細節累積起來的時候,節省掉的效能其實也是很可觀的,就讓我們來看一下Vue3 中對於效能上面的優化的操作吧!

MIKE VUE

第一種 : computed 用的好,資料處理沒煩惱!

我在前面的章節不知道介紹過幾次 computed 了,但是 computed 是真的很重要,所以才又提到了,我們再來複習一下 computed 這個功能,我們再來看一下官方的說明。

computed 是一個計算屬性,設計它的初衷是用於簡單運算的,在模板中放入太多的邏輯會讓模板過重且難以維護,所以會需要透過computed 來重新處理過那些複雜的資料,官方文件有提到說

computed 屬性是基於Vue綁定的資料依賴關係緩存的
官方文件 : https://v3.vuejs.org/guide/computed.html#computed-properties

這意味者 computed 只在透過 Vue 綁定的資料發生改變時它們才會重新去執行處理計算,所以今天你的資料只要是 Vue 綁定的資料,都可以被計算處理過。

我們在前面已經知道透過 computed 的緩存,可以避免重複性的函式執行,減少渲染上面的效能浪費,除來邏輯上面的計算以外,computed也可以搭配 reactive來使用,可以更方便的去重組資料,又不用重新去宣告新的 ref 變數來儲存,我們來看一下下面這個例子。

下面這是我打非同步所取得的資料格式。

[
  {
    createdAt: "2021-09-16T01:52:45.780Z",
    name: "Regina Dooley",
    avatar: "https://cdn.fakercloud.com/avatars/kolmarlopez_128.jpg",
    post_date: 1631766938728,
    photo: "http://placeimg.com/640/480",
    content: "connect redundant driver",
    type: "cat",
    id: "1"
  },
  {
    createdAt: "2021-09-16T00:20:33.453Z",
    name: "Tricia Lang",
    avatar: "https://cdn.fakercloud.com/avatars/vaughanmoffitt_128.jpg",
    post_date: 1631766938728,
    photo: "http://placeimg.com/640/480",
    content: "index auxiliary alarm",
    type: "fish",
    id: "2"
  },
	// 以下省略
]

我現在有個需求,我希望依照現在拿到的資料,另外再產生三份不同的資料,一個是把資料變成map的資料格式,另外兩個是依照 type 來產生另外兩個分類好的 array,如果是一般的做法肯定會寫好幾個 function 或是宣告幾個專門來處理及存放資料的變數,然後當今天重新再打一次 API 的時候,你的資料還要同時同步去做處理轉換格式分類這些事情.這些我們全部可以透過 computed+ reactive 來組合完成。

我們來看看 code

const userInfo = reactive({
  data: [],
  dataMap: computed(() => {
    const map = {};
    for (const item of userInfo.data) {
      map[item.id] = item;
    }
    return map;
  }),
  catType: computed(() => {
    return userInfo.data.filter((item) => item.type === "cat");
  }),
  fishType: computed(() => {
    return userInfo.data.filter((item) => item.type === "fish");
  }),
});

你會發現我這邊在 reactive 裡面定義的資料用了 computed 來做計算,所以今天我打 API 拿資料的時候,我只要去負責更新 data 的資料就好,其他的資料會因為data被更新了後,computed就會自動幫我重新計算,所以今天如果資料沒有被改變,它也就不會重新去執行,你可以看看實際完成的範例,透過這樣的方式定義資料我們就只要專注在更新資料,其他處理交給 computed

codesandbox 範例:https://codesandbox.io/s/vue-performance-update1-0fqru?file=/src/App.vue

Computed vs Methods

前面的章節我們有提到 Computed 也有許多地方跟 Methods 很像,而且 Methods 能傳入參數,文件上面也有特別針對這件事情去說明,有興趣的可以看這邊。

官方文件: https://v3.vuejs.org/guide/computed.html#computed-caching-vs-methods
上次提到的地方:https://ithelp.ithome.com.tw/articles/10262040

第二種 : 唯一的 key 就是為了讓 Vue 記住你!

key 是一個在 vue 裡面比較特殊的 attribute,專門用來比較 Virtual DOM 的新舊節點,所以當今天使用了 key 的話,他會依照 key 的順序變化重新排列元件,並且那些不存在的 key 的元件給銷毀,如果不給 key ,Vue 就會大範圍修改或是重複更新相同的元件,造成不必要的效能浪費。

key 是需要唯一的識別碼,可以用 number 或是 string。

最常會用到 key 的地方就是 v-for 的列表這邊。

<ul>
  <li v-for="item in DataArray" :key="item.id">...</li>
</ul>

在很多網站上面都會有需要資料的列表,還有列表之間的操作,不管是刪除、新增、還是重新排序、甚至是修改,這些的操作都會影響到列表的更新,所以今天只要透過 key 的綁定,vue 就會知道被修改的是那一個 DOM,進而只去對該物件修改而已,就不會大範圍的去重新渲染沒有改變資料的地方了。

很多人會說既然 key 是需要唯一的值,那我就拿 v-for 的索引來做就好了啊! 拜託不要阿!

// 錯誤的寫法
<ul>
  <li v-for="(item, idx) in DataArray" :key="idx">...</li>
</ul>

你拿陣列的索引來當作你的 key ,但是今天遇到了排序或是刪除的情況,索引是跟著 array 的,所以這時候的執行就會發生問題,拜託千萬不要用索引當作你的key,甚至我還看過下面這種寫法

// 錯誤的寫法
<ul>
  <li v-for="(item, idx) in DataArray" :key="'test-' + idx">...</li>
</ul>

這樣有差嗎XDD 還不是拿索引來作為key的其中一個元素,所以開發上面要特別注意。

第三種 : 看好了世界! 關於 v-once 我只執行一次 !

我們再做網頁的時候常常會有很多頁面或是元件沒有需要動態去替換,甚至是寫死的內容,但是往往會因為周遭的組件或是父層而影響到去重新渲染。我們可以再組件或是 DOM元素上面使用 v-once這個方法,來達到這些掛載 v-once的組件不會重複的去渲染,它就只會渲染一次,下了 v-once的組件或是DOM元素內的所有子節點也都不會被重新渲染,可以說是節省掉許多額外的效能消耗。

<header v-once>
    <img src="logo.svg" class="avatar" />
    <nav>
        <a>HOME</a>
        <a>ABOUT</a>
        <a>ADDRESS</a>
    </nav>
</header>

例如我們網站的 header 或是 footer 都很常內容都是固定的,所以這類型就很適合使用 v-once這個功能。

<ul>
  <li v-for="i in list" v-once>
  	// ...
  </li>
</ul>

或是很多的列表其實也不需要做更新,所以也很常利用 v-forv-once來做搭配,這樣一來頁面其他的地方更新,也不會來影響到這些原本就是靜態的內容。

第四種 : 渲染優化的新功能 v-memo

v-memo 是 vue3.2 才有的一個新功能,主要功能跟 v-once 非常類似,但不一樣的地方是 v-once 是只要用了就會直接停止渲染後續更新行為,但是v-memo 是有條件的停止後續的渲染,我們來看一下官網上面的案例是如何使用。

<div v-memo="[valueA, valueB]">
    // ...
</div>

這邊的 v-memo可以傳入一筆或多筆的資料去進行記憶比對,當如果陣列裡面每一個value跟上次渲染的時候一樣,它的所有子元件跟節點就都不會重新去渲染,所以今天如果是裡面的內容會依照資料的不同而進行渲染的話, v-memo的做法就可以再一定程度上面達到渲染優化的效果。

v-memo官方文件: https://v3.vuejs.org/api/directives.html#v-memo

But...

我嘗試了用 v-memo 寫一個範例,但是不管我怎麼測試都還是有一點狀況,甚至也有國外的開發者在 issues上面去詢問有關 v-memo 使用上的問題,所以我猜測可能是還有一些問題需要被解決,我在寫這篇文章的時候 Vue 是3.2.11版本,希望之後的版本可以解決這個問題,或是官方可以針對 v-memo 再多做一些詳細的解說及用法,之後我有實際測試出來更詳細的資訊我會再補上來的。

根據 Vue 的爸爸 Evan You 所說,v-memo 的功能出現大幅度提高了 Vue 在前端框架效能速度的排名,成為最快的主流框架之一。

VUE

原文 : https://blog.vuejs.org/posts/vue-3.2.html

先告一個段落

我們今天說了幾個在Vue的開發上面能針對操作上面的更新渲染的效能提升方式,希望大家在開發的時候也能多多注意這些細節,好啦! 我們明天見吧!

QRcode

那如果對於Vue3不夠熟的話呢?

Ps. 購買的時候請登入或註冊該平台的會員,然後再使用下面連結進入網站點擊「立即購課」,這樣才可以讓我獲得更多的課程分潤,還可以幫助我完成更多豐富的內容給各位。

我有開設了一堂專門針對Vue3從零開始教學的課程,如果你覺得不錯的話,可以購買我課程來學習
https://hiskio.com/bundles/9WwPNYRpz?s=tc

那如果對於JS基礎不熟的朋友,我也有開設JS的入門課程,可以參考這個課程
https://hiskio.com/bundles/b9Rovqy7z?s=tc

訂閱Mike的頻道享受精彩的教學與分享

Mike 的 Youtube 頻道
Mike的medium
MIke 的官方 line 帳號,好友搜尋 @mike_cheng


上一篇
[重構倒數第12天] - Vue3 directive 與 Skeleton 實戰組合應用
下一篇
[重構倒數第10天] - 行動裝置上面的 Touch 跟 Click
系列文
[ 重構倒數30天,你的網站不Vue白不Vue ] 32
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言