Vue2 和 Vue3 效能比較小實驗

notebin發表於2023-02-24

分別使用 Vue2 和 Vue3 建立一個元件,用一個物件陣列作為元件的狀態,以它的長度作為變數,考察 Vue2 和 Vue3 效能。

記憶體佔用

陣列長度Vue2Vue3
110.2 MB11.1 MB
10 00017.9 MB12.1 MB
100 00067.4 MB14.4 MB
1 000 000568 MB36.0 MB

初始化時間

陣列長度Vue2Vue3
17.2 ms7.8 ms
10 000110 ms6.9 ms
100 000803 ms6.7 ms
1 000 0002282 ms7.0 ms

測試程式碼

Vue2

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
  <div id="app">{{ message }}</div>

  <script>
    const len = 1000000
    const arr = new Array(len)
    for (let i = 0; i < len; i++) {
      arr[i] = { id: i, name: 'test' }
    }
    
    console.time('vue2:')
    new Vue({
      el: '#app',
      data() {
        return {
          message: 'Hello Vue!',
          arr
        }
      },
      created() {
        console.timeEnd('vue2:')
      }
    })
  </script>
</body>
</html>

Vue3

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
</head>
<body>
  <div id="app">{{ message }}</div>

  <script>
    const { createApp } = Vue

    const len = 1000000
    const arr = new Array(len)
    for (let i = 0; i < len; i++) {
      arr[i] = { id: i, name: 'test' }
    }

    console.time('vue3:')
    createApp({
      data() {
        return {
          message: 'Hello Vue!',
          arr
        }
      },
      created() {
        console.timeEnd('vue3:')
      }
    }).mount('#app')
  </script>
</body>
</html>

推測

Vue2 使用Object.defineProperty()建立響應式屬性,初始化時,除了遍歷propsdata的每個屬性,還會深度遍歷子物件和子陣列,重新定義它們的屬性,並建立如ObserverDep例項,來觀察屬性變化,並且Object.defineProperty()重寫的getset方法也是掛載在例項上。深度遍歷加上建立這些例項的花銷遠大於原始物件,於是,可以看到 Vue2 無論是記憶體,還是初始化時間隨著陣列長度增加猛漲,和 Vue3 產生了明顯的差距。

當陣列長度到達 100 萬,Vue3 記憶體僅增加 25 MB,但 Vue2 記憶體暴增了 500+ MB,這些多出來的記憶體便是建立這些例項產生的額外開銷。觀察 Vue2 記憶體快照,發現 Vue2 建立了 100 萬個Observer例項,相當於每個物件一個(另外三個Observer例項分別用於觀察元件propsdata和陣列本身)。陣列中每個物件有兩個屬性,相應建立 200 萬個Dep例項,100 萬個Observer例項相應建立了100 萬個Dep例項,共建立超過 300 萬個Dep例項。

記憶體快照

初始化時間來看,Vue3 幾乎不受陣列長度影響,而 Vue2 則隨陣列長度明顯變長。這是因為 Vue3 使用Proxy類實現響應式,系統會代理響應式物件的操作,如元件的propsdata,包括屬性讀取、賦值等,不會進行深度遍歷。當讀取響應式物件的屬性時,才會建立Dep例項,如果讀取的屬性值也是物件時,再將這個物件響應式化,可以說 Vue3 是“懶”響應式。因此,初始化過程中 Vue3 執行時間幾乎不變,如果不去操作這些屬性,也幾乎不會有太多記憶體消耗。

列表渲染

分別使用 Vue2 和 Vue3 渲染 50000 個元素:

<ul>
  <li v-for="item in arr">{{ item.id }}</li>  
</ul>

可以看出,無論是記憶體佔用或渲染完成時間,Vue3 更佔優勢:

Vue2Vue3
記憶體124 MB53.1 MB
渲染完成時間862ms284 ms

相關文章