1. 程式人生 > 程式設計 >Vue優化:常見會導致記憶體洩漏問題及優化詳解

Vue優化:常見會導致記憶體洩漏問題及優化詳解

如果你在用 Vue 開發應用,那麼就要當心記憶體洩漏的問題。這個問題在單頁應用 (SPA) 中尤為重要,因為在 SPA 的設計中,使用者使用它時是不需要重新整理瀏覽器的,所以 JavaScript 應用需要自行清理元件來確保垃圾回收以預期的方式生效。因此在vue開發過程中,你需要時刻警惕記憶體洩漏的問題,這些記憶體洩漏往往會發生在使用 Vue 之外的其它進行 DOM 操作的三方庫時,請確保測試應用的記憶體洩漏問題並在適當的時機做必要的元件清理。

下面是我開發過程中遇到,並查資料總結的記憶體洩漏問題,會持續更新中

一、vue自定義指令給元素繫結事件,卻沒有解綁事件

這個問題見上篇部落格,vue自定義指令導致的記憶體洩漏問題解決

二、v-if指令產生的記憶體洩露

v-if也是一個容易產生記憶體洩漏的地方。因為:

1、v-if繫結到false的值,但是實際上dom元素在隱藏的時候沒有被真實的釋放掉

2、就是非常常見的比如我們通過v-if刪除了父級元素,但是並沒有移除父級元素裡的dom片段。通常產生於使用第三方庫的時候,比如下面的示例中,我們載入了一個帶有非常多選項的選擇框,然後我們用到了一個顯示/隱藏按鈕,通過一個 v-if 指令從虛擬 DOM 中新增或移除它。這個示例的問題在於這個 v-if 指令會從 DOM 中移除父級元素,但是我們並沒有清除由 Choices.js 新新增的 DOM 片段,從而導致了記憶體洩漏。

<link rel="stylesheet prefetch" href="https://joshuajohnson.co.uk/Choices/assets/styles/css/choices.min.css?version=3.0.3" rel="external nofollow" >
<script src="https://joshuajohnson.co.uk/Choices/assets/scripts/dist/choices.min.js?version=3.0.3"></script>

<div id="app">
 <button v-if="showChoices" @click="hide">Hide</button>
 <button v-if="!showChoices" @click="show" >Show</button>
 <div v-if="showChoices">
 <select id="choices-single-default"></select>
 </div>
</div>
new Vue({
 el: "#app",data: function () {
 return {
  showChoices: true
 }
 },mounted: function () {
 this.initializeChoices()
 },methods: {
 initializeChoices: function () {
  let list = []
  // 我們來為選擇框載入很多選項
  // 這樣的話它會佔用大量的記憶體
  for (let i = 0; i < 1000; i++) {
  list.push({
   label: "Item " + i,value: i
  })
  }
  new Choices("#choices-single-default",{
  searchEnabled: true,removeItemButton: true,choices: list
  })
 },show: function () {
  this.showChoices = true
  this.$nextTick(() => {
  this.initializeChoices()
  })
 },hide: function () {
  this.showChoices = false
 }
 }
})

解決例項:在上述的示例中,我們可以用 hide() 方法在將選擇框從 DOM 中移除之前做一些清理工作,來解決記憶體洩露問題。為了做到這一點,我們會在 Vue 例項的資料物件中保留一個屬性,並會使用 Choices API 中的 destroy() 方法將其清除。

new Vue({
 el: "#app",data: function () {
 return {
  showChoices: true,choicesSelect: null
 }
 },methods: {
 initializeChoices: function () {
  let list = []
  for (let i = 0; i < 1000; i++) {
  list.push({
   label: "Item " + i,value: i
  })
  }
  // 在我們的 Vue 例項的資料物件中設定一個 `choicesSelect` 的引用
  this.choicesSelect = new Choices("#choices-single-default",hide: function () {
  // 現在我們可以讓 Choices 使用這個引用
  // 在從 DOM 中移除這些元素之前進行清理工作
  this.choicesSelect.destroy()
  this.showChoices = false
 }
 }
})

三、vue-router跳轉到別的元件導致的內容洩漏

在上述示例中,我們使用了一個 v-if 指令產生記憶體洩漏,但是一個更常見的實際的場景是使用 Vue Router 在一個單頁應用中路由到不同的元件。

就像這個 v-if 指令一樣,當一個使用者在你的應用中導航時,Vue Router 從虛擬 DOM 中移除了元素,並替換為了新的元素。但是其子元素dom片段也並沒有銷燬。

Vue 的 beforeDestroy() 生命週期鉤子是一個解決基於 Vue Router 的應用中的這類問題的好方法。我們可以將清理工作放入 beforeDestroy() 鉤子,像這樣:

beforeDestroy: function () {
 this.choicesSelect.destroy()
}
  

所以最正確的解決方案就是:首先,v-if置為false前先刪除建立的dom片段;其次,路由跳出吃,在beforeDestroy鉤子函式裡面判斷choicesSelect是否銷燬,沒銷燬則銷燬。

還有一個替代方案:

我們已經討論了移除元素時的記憶體管理,但是如果你打算在記憶體中保留狀態和元素該怎麼做呢?這種情況下,你可以使用內建的 keep-alive 元件。

當你用 keep-alive 包裹一個元件後,它的狀態就會保留,因此就留在了記憶體裡。

<button @click="show = false">Hide</button>
<keep-alive>
 // <my-component> 即便被刪除仍會刻意保留在記憶體裡
 <my-component v-if="show"></my-component>
</keep-alive>

這個技巧可以用來提升使用者體驗。例如,設想一個使用者在一個文字框中輸入了評論,之後決定導航離開。如果這個使用者之後導航回來,那些評論應該還保留著。

一旦你使用了 keep-alive,那麼你就可以訪問另外兩個生命週期鉤子:activated和 deactivated。如果你想要在一個 keep-alive 元件被移除的時候進行清理或改變資料,可以使用 deactivated 鉤子。

deactivated: function () {
 // 移除任何你不想保留的資料,或者銷燬可能產生記憶體洩漏的地方
}

以上這篇Vue優化:常見會導致記憶體洩漏問題及優化詳解就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支援我們。