$emit 导致内存泄漏 - Vue.js [英] $emit causing memory leak - Vue.js

查看:82
本文介绍了$emit 导致内存泄漏 - Vue.js的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有两个组件.一个父母和一个孩子.父级基于 v-if 加载子级.然后孩子通过$emit发送一个事件告诉父母移除孩子.

简单地说.

家长:

data() {返回 {显示:假}},//模板:<div><div @click="show = !show">切换</div><子组件v-if="显示"@close="show = false"/>

孩子:

模板:<div>部分内容<div @click="$emit('close')">关闭</div>

问题在于,当 $emit('close') 被触发时,子组件会从 DOM 中移除,但组件不会从内存中清除.

如果父级使用 toggle 按钮移除子级,它确实会从内存中清除子级.

我也尝试过使用 Vuex store$root.data 但这也会导致内存泄漏.

换句话说,如果子进程向父进程发出信号表示它应该被移除,它就会被保存在内存中.但是,如果父级直接删除子级(没有来自子级的任何信号),它将从内存中删除...

任何想法为什么会发生这种情况以及我应该怎么做才能防止这种内存泄漏?有必要让孩子表示它要被移除了.

- 代码笔中的演示.https://codepen.io/tomshort5/pen/BaBLXvb

内存快照

通过在某些操作后制作内存快照可以最好地看到这一点.当页面加载时,我们有一个 Vue 实例.

点击切换后,VueComponent 就按预期创建了.

通过事件触发child被移除后,VueComponent并没有从内存中移除.将其与再次单击切换"进行比较时,它确实显示组件已从内存中删除.

解决方案

我有部分解释.

似乎有什么东西保留了对最后一个被点击的 DOM 节点的引用.因此,如果您单击 Close,它将抓住对该文本节点的引用.文本节点的父节点是

并且

有一个指向 Vue 组件的点击监听器.组件本身已被销毁,只是无法进行 GC.

如果您点击 Toggle,它会保留对 Toggle 文本节点的引用.由于该节点位于 DOM 树的不同部分,因此它不会通过单击侦听器保留对元素的任何引用.Vue 组件GC 成功.

我无法准确确定是什么保留了对上次单击的节点的引用.堆快照并不是特别有用.它只是显示 InternalNodewindow 连接到相关的文本节点.

我确实在没有 Vue 的情况下组合了一个页面来探索这个.我的实验表明,即使 Vue 不在页面上,也会保留对上次点击节点的引用.

这里的内存泄漏只是非常暂时的.在页面上的任意位置再单击一次,似乎就足以修复它.与我的理论一致,这更新了上次点击的节点"引用,允许对分离的 DOM 节点和 Vue 组件进行 GC.

I have two components. A parent and a child. The parent loads the child based on v-if. Then the child sends an event through $emit to tell the parent to remove the child.

So simply put.

PARENT:

data() {
    return {
        show: false
    }
},
// template: 
<div>
    <div @click="show = !show">Toggle</div>
    <child-component
        v-if="show"
        @close="show = false"
   />
</div>

CHILD:

template: 
<div>
    Some Content
    <div @click="$emit('close')">Close</div>
</div>

The problem is that when $emit('close') is fired, the child is removed from the DOM but the component is not cleared from memory.

If the parent removes the child using the toggle button, it does clear the child from memory.

I have also tried using Vuex store and $root.data but this also causes a memory leak.

In other words, it seems that if the child signals to the parent that it should be removed, it is kept in memory. However, if the parent removes the child directly (without any signal from the child) it's removed from memory...

Any ideas why this happens and what I should do to prevent this memory leak? It's necessary that the child signal it's removal.

[EDIT] - DEMO IN CODE PEN. https://codepen.io/tomshort5/pen/BaBLXvb

Memory snapshots

This is best visible by making memory snapshots after certain actions. When the page loads, we have a single Vue instance.

After clicking toggle, a VueComponent is created as expected.

After triggering the child to be removed through an event, the VueComponent is not removed from memory. When comparing it to clicking "Toggle" again, it does show the component getting removed from memory.

解决方案

I have a partial explanation.

It seems that something is holding onto a reference to the last DOM node that was clicked. So if you click on Close it will grab hold of a reference to that text node. The text node's parent is the <div> and the <div> has a click listener pointing back to the Vue component. The component itself has been destroyed, it just can't be GCed.

If instead you click on Toggle it retains a reference to the Toggle text node. As that node is in a different section of the DOM tree it doesn't retain any reference to the element with the click listener. The Vue component is successfully GCed.

I haven't been able to establish precisely what retains this reference to the last clicked node. The heap snapshot isn't particularly helpful. It just shows InternalNode connecting window to the relevant text node.

I did put together a page to explore this without Vue. My experiments suggested that retaining a reference to the last clicked node is something that occurs even when Vue is not on the page.

The memory leak here is only very temporary. Clicking one more time, anywhere on the page, seems to be enough to fix it. Consistent with my theory, that updates the 'last clicked node' reference, allowing the detached DOM nodes to be GCed and the Vue component with it.

这篇关于$emit 导致内存泄漏 - Vue.js的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆