咱們一個後臺,在切換一些標籤頁的時候,是使用的 keep-alive
緩存的標籤頁,也使用了 include
屬性來決定哪一個頁面進行緩存,而標籤頁的切換其實是路由的切換,也就是說打開一個新標籤頁的時候,url 會跟着變化,老的標籤頁若是在 keep-alive
的 include
範圍內那就會緩存下來。
而後客服人員就反饋頁面開的久了就會崩潰,由於他們基礎上不會刷新頁面(工做須要),又總有切換標籤的習慣,最後致使內存愈來愈大最後崩潰。javascript
這個項目是基於一個開源 vue
後臺框架:https://github.com/PanJiaChen/vue-element-admin
,而後代碼一直由幾個後端開發維護的!因此後端沒找出問題在哪,而後就我來接手這個問題了。
寫文章時,標籤里居然沒有 vue
這一項,差評!vue
先梳理下業務邏輯:從業務場景來講,咱們在標籤頁之間切換時,若是剛進入的這個標籤頁已被緩存了,那被緩存的標籤頁就直接拿出來展現就行,而關閉這個標籤頁的時候就應該銷燬對應的組件。java
花了點時間查看了一下代碼,發現問題在於關閉標籤頁的時候,雖然這個頁面沒在 keep-alive
的 include
裏了,可是組件也沒有被銷燬掉,仍是在緩存狀態,咱們能夠經過 Vue Devtools
插件看到關閉後的標籤頁對應的組件一直還存在着:git
固然,在這塊 keep-alive
自己的邏輯我以爲是沒問題的,主要是咱們項目比較複雜,緩存的組件太多了並且會一直增長,因此最終致使崩潰。github
既然問題已經定位了,那就好解決問題了,只須要在關閉標籤頁的時候把對應的組件也銷燬掉就行了。vuex
通過網上一翻查找,發現銷燬一個組件可使用: this.$destroy(‘組件名’)
來銷燬。後端
先說下大概思路:keep-alive
的 include
裏存的實際上是一個 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
來緩存組件中的數據,當須要從新顯示數據時再把數據取出來並從新渲染。固然,這是一個比較大的工程!