Vue在IE Edge浏览器中内存泄露
发布于 4个月前 作者 sharkdbj 633 次浏览 来自 问答

问题场景描述

在IE edge浏览器下,父子组件的场景,子组件依赖父组件的状态,子组件控制父组件状态变化从而反馈给子组件的展示变化,子组件通过v-if模式存在于视图中,父组件通过状态控制子组件的v-if状态变换。子组件控制父组件状态完成子组件数据填充后,父组件切换子组件的v-if状态,子组件占用dom结构被清理。此时,子组件存在时的内存占用未被释放,当父组件再次回切v-if状态时,子组件重新展示,内存飙升,重复几次切换后,内存飙升明显,页面卡顿。

父组件代码

<template>
  <div>
    <div>
        <button @click="aa = true">xx</button>
        <button @click="aa = false">yy</button>
        
        <x :init="tab1Click" :tableData="tableData1" :items="items1" v-if="aa"></x>
        <y :init="tab2Click" :tableData="tableData2" :items="items2" v-else></y>
    </div>
  </div>
</template>
<script>
    import x from './component/x1.vue'
    import y from './component/y1.vue'
    export default {
        data () {
            return {
                aa: true,
                tableData1: [],
                tableData2: [],
                items1: [],
                items2: []
            }
        },
        methods: {
            tab1Click () {
              this.tableData1 = []
              this.items1 = []
              setTimeout(() => {
                this.tableData1 = [
                  {key: 'x1', a:'a', b:2, c:3, d:4, e: 5},
                  {key: 'x2', a:'a', b:2, c:3, d:4, e: 5},
                  {key: 'x3', a:'a', b:2, c:3, d:4, e: 5},
                  {key: 'x4', a:'a', b:2, c:3, d:4, e: 5},
                  {key: 'x5', a:'a', b:2, c:3, d:4, e: 5},
                  {key: 'x6', a:'a', b:2, c:3, d:4, e: 5},
                  {key: 'x7', a:'a', b:2, c:3, d:4, e: 5},
                  {key: 'x8', a:'a', b:2, c:3, d:4, e: 5},
                  {key: 'x9', a:'a', b:2, c:3, d:4, e: 5},
                  {key: 'x10', a:'a', b:2, c:3, d:4, e: 5}
                ]
                this.items1 = [
                  {title: 'a', prop: 'a'},
                  {title: 'b', prop: 'b'},
                  {title: 'c', prop: 'c'},
                  {title: 'd', prop: 'd'},
                  {title: 'e', prop: 'e'}
                ]
              }, 1000)
            },
            tab2Click () {
              this.tableData2 = []
              this.items2 = []
              setTimeout(() => {
                this.tableData2 = [
                  {key: 'x1', a:'a', b:2, c:3, d:4, e: 5},
                  {key: 'x2', a:'a', b:2, c:3, d:4, e: 5},
                  {key: 'x3', a:'a', b:2, c:3, d:4, e: 5},
                  {key: 'x4', a:'a', b:2, c:3, d:4, e: 5},
                  {key: 'x5', a:'a', b:2, c:3, d:4, e: 5},
                  {key: 'x6', a:'a', b:2, c:3, d:4, e: 5},
                  {key: 'x7', a:'a', b:2, c:3, d:4, e: 5},
                  {key: 'x8', a:'a', b:2, c:3, d:4, e: 5},
                  {key: 'x9', a:'a', b:2, c:3, d:4, e: 5},
                  {key: 'x10', a:'a', b:2, c:3, d:4, e: 5}
                ]
                this.items2 = [
                  {title: 'a', prop: 'a'},
                  {title: 'b', prop: 'b'},
                  {title: 'c', prop: 'c'},
                  {title: 'd', prop: 'd'},
                  {title: 'e', prop: 'e'}
                ]
              }, 1000)
            }
        },
        components: {
            x,
            y
        }
    }
</script>

子组件代码

<template>
<div>
  <table>
    <tr v-for="row in tableData" :key="row.key">
      <td v-for="item in items" :key="item.prop"> 
        <div v-for="i in 100">
          <input type="text" :value="row[item.prop]" />
        </div>
      </td>
    </tr>
  </table>
</div>
</template>
<script>
  export default {
    props: ['tableData', 'items', 'init'],
    mounted () {
      this.init()
    }
  }
</script>

可运行案例地址:

demo

初步设想

v-if状态变化后,dom被销毁,但是父组件中的状态与子组件绑定后,存在引用联系,导致即使dom销毁,引用联系仍旧存在内存中无法释放。

4 回复

应该是文中提到的 子组件控制父组件状态变化从而反馈给子组件的展示变化 可以尝试使用 父组件控制父组件状态变化从而反馈给子组件的展示变化

@ab8512感谢您的回复,我一直在思考为何会出现这种情况,这个场景是问题的根源,最初出现这个问题是在vuex结合vue使用的时候,vue的实例中要调用mutions变更状态,这个状态是存在全局的,不只是父组件了,例子里的父组件其实是做了个状态共享。也就是说不论是父组件的模式形成状态共享还是vuex的模式,ie下都会存在内存泄露的现象,这个问题个人感觉对vue的冲击很大。

内存池露对于web来说致命的, 像这种致命的问题不应该是出现在一个相对成熟的框架当中, 而内存池露一般来说使用不当造成的, 个人觉得楼主应该先从使用上寻找问题, 可以分片查找, 可以使用排除法查找, 或者极简化测试一下

@ab8512 再次感谢您的回复,问题中给的示例已经是简化过了的,而且我自己也一直在分析,只要在vue实例销毁前,把子组件的数据状态与父组件的数据状态断开引用关系即可防止内存泄露,也就是说如果子组件们不使用父组件的状态,自己通过data管理私有状态,是不存在该问题的。但是,全部组件状态都自己管,在做父子、兄弟组件间的通信时,是不方便的,这也是vuex出现带来的一个好处,统一管理状态。现在在看源码找答案,我始终认为这是vue底层造成的。

回到顶部