vue 裏主動銷燬 keep-alive 緩存的組件

問題產生的背景

咱們一個後臺,在切換一些標籤頁的時候,是使用的 keep-alive 緩存的標籤頁,也使用了 include 屬性來決定哪一個頁面進行緩存,而標籤頁的切換其實是路由的切換,也就是說打開一個新標籤頁的時候,url 會跟着變化,老的標籤頁若是在 keep-aliveinclude 範圍內那就會緩存下來。
而後客服人員就反饋頁面開的久了就會崩潰,由於他們基礎上不會刷新頁面(工做須要),又總有切換標籤的習慣,最後致使內存愈來愈大最後崩潰。javascript

依賴環境

這個項目是基於一個開源 vue 後臺框架:https://github.com/PanJiaChen/vue-element-admin,而後代碼一直由幾個後端開發維護的!因此後端沒找出問題在哪,而後就我來接手這個問題了。
寫文章時,標籤里居然沒有 vue 這一項,差評!vue

定位問題

先梳理下業務邏輯:從業務場景來講,咱們在標籤頁之間切換時,若是剛進入的這個標籤頁已被緩存了,那被緩存的標籤頁就直接拿出來展現就行,而關閉這個標籤頁的時候就應該銷燬對應的組件。java

clipboard.png

花了點時間查看了一下代碼,發現問題在於關閉標籤頁的時候,雖然這個頁面沒在 keep-aliveinclude 裏了,可是組件也沒有被銷燬掉,仍是在緩存狀態,咱們能夠經過 Vue Devtools 插件看到關閉後的標籤頁對應的組件一直還存在着:git

clipboard.png

固然,在這塊 keep-alive 自己的邏輯我以爲是沒問題的,主要是咱們項目比較複雜,緩存的組件太多了並且會一直增長,因此最終致使崩潰。github

解決問題

既然問題已經定位了,那就好解決問題了,只須要在關閉標籤頁的時候把對應的組件也銷燬掉就行了。vuex

通過網上一翻查找,發現銷燬一個組件可使用: this.$destroy(‘組件名’) 來銷燬。後端

先說下大概思路:keep-aliveinclude 裏存的實際上是一個 vuex 中的一個數據源(數據源保存的是路由名稱),當關閉標籤頁時,這個數據源中的一項會被移除。這以前,咱們在組件裏監聽到這個數據源的變化,若是此組件對應的路由(這個路由應在 mounted 的時候保存下來)已經不在數據源中了,那就應該銷燬此組件。緩存

代碼大概以下:框架

const mixin = {
  data() {
    return {
      routePath: ''
    }
  },
  mounted() {
    this.routePath = this.$route.path
  },
  computed: {
    visitedViews() {
      return this.$store.state.tagsView.visitedViews
    }
  },
  watch: {
    visitedViews(value) {
      if(value 裏沒有了 routePath 這一項)
        this.$destroy(this.$options.name)
      }
    }
  }
}

export default mixin

這一段代碼單獨拎出來了,而後在須要緩存的組件裏使用 mixins 混入到組件對象中,這樣組件中要添加的代碼量就比較少了。dom

更改後通過測試,關閉標籤頁後對應的組件就會被銷燬掉,使用 Vue Devtools 能看的很清楚。

更多思考

在咱們後臺操做這麼頻繁的業務場景下,使用 keep-alive 其實並非一個好的選擇。

在咱們修復這個問題後,咱們經過控制檯裏的 Memory 查看頁面內存的變化時,發現組件即使被銷燬,也要通過一段時間才能回收完,當咱們在這一段時間一直建立/打開新的標籤頁時,內存仍是會在短期內高漲。並且有時候,內存在通過一段時間後也並無回收掉。

keep-alive 本質上是把整個 dom 節點及對應的事件等都緩存下來了,當這樣的組件不少的時候,天然會佔用不少內存。而若是咱們只緩存這個組件中的數據,在須要這個組件再次顯示的時候再臨時渲染那確定要節省不少內存的,畢竟數據佔的空間其實很小的,而渲染組件要花的時間也不會很長(只要組件不是特別特別複雜)。

因此,下一階段的優化工做就是把 keep-alive 去掉,而後使用 vuex 來緩存組件中的數據,當須要從新顯示數據時再把數據取出來並從新渲染。固然,這是一個比較大的工程!

相關文章
相關標籤/搜索