Vue優化:常見會導致內存泄漏問題及優化


簡介

1 .主要是在單頁應用中,用戶不會刷新瀏覽器,所以js應用需要自己清理組件來確保垃圾回收以預期的方式生效
2 . 使用其他第三方可能會創建DOM的插件的時候,在清除DOM的時候一定要保證完全清除dom片段,不要造成殘留。
3 .頻繁調用創建的代碼,但是一直沒有清除的話就會造成內存飆升,而且一直不會釋放.一定要destory掉,比如echarts那個插件,切換到其他界面,不需要改組件的時候一定要destory掉
4 .尤其是手機或者其他性能不是特別好的設備尤為重要,或者應用內有很多應用內的導航么?這都需要良好的內存管理
5 .

v-if指令產生的內存泄露

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

Vue router

1 .當用戶在你的應用中導航的時候,vue router從虛擬dom中移除了元素,並替換為了新的元素,Vue的beforeDestory()鈎子函數就是一個解決清理工作的好地方,我們可以將清理dom的操作都放到這個里面
2 .

替代方法

1 .在移除元素的時候的內存管理如上
2 .如果有需要在內存中保留狀態和元素的時候,使用內建的keep-alive組件

1 .keep-alive包裹的組件,狀態會被保留在內存里面
2 .可以用來提升用戶體驗,當一個用戶在文本框中輸入了文本,再一次導航回來,文本還在,豈不美滋滋
3 .這個時候移除的時候就要選取 deactivated鈎子來移除元素了

3 .Vue中的內存泄露往往會發生在Vue之外其他DOM操作的第三方庫,一定要確保測試應用的內存泄露問題並在適當的時候做組件清理

 
 

 


 

如果你在用 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">
<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
    }
  },
  mounted: function () {
    this.initializeChoices()
  },
  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", {
        searchEnabled: true,
        removeItemButton: true,
        choices: list
      })
    },
    show: function () {
      this.showChoices = true
      this.$nextTick(() => {
        this.initializeChoices()
      })
    },
    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 () {
  // 移除任何你不想保留的數據,或者銷毀可能產生內存泄漏的地方
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM