中国台湾问题,从来都不是“打不打”的问题,而是何时回归的问题。之所以台湾问题拖到了现在,并不是因为有美国的牵制。最根本的原因,是大陆想要通过和平的手段...
2025-07-27 0
原有的结论有问题,这是最新的弥补篇。如果您还没有看过,可以先看新篇提出的问题再看这个。如果您已看过,可以看下最新篇。希望不会给您带来困扰,随时接受大佬们的批评。
新篇戳这里。更崩溃!!感觉被偷家了!Element-plus 组件测试的后续~
---------------------以下为原文---------------------------
进来着急的前端佬,我直接抛出结论吧!
Element-plus 的组件,经过测验,如下组件存在内存泄漏。如下:
验证环境为:
Vue Version: 3.5.13
Element Plus Version: 2.9.7
Browser / OS: window 10 / Edge 134.0.3124.85 (正式版本) (64 位)
Build Tool: Webpack
不排查 ElementUI 也存在这个问题。
好了。接下来细细聊。
为什么检测到这种问题?主要因为一个项目引用了 Element-plus。然后,你懂的,买的人永远都会想要最好的,然后买的人就这么一顿狂点 Web 页面,看见内存占用飙到老高。
于是...前端佬都懂的,来活了。
一开始我是不敢怀疑这种高 star 开源组件的。总以为自己是写的代码有问题。
详细代码就不贴了,主要用 ElDialog 组件,封装成一个命令式的 Dialog 组件,避免频繁的使用 v-modal 参数。
然后,就直接怀疑上这个组件了。
经过测试,果不其然,从关闭到销毁,会导致内存猛增,因为 Dialog 中有各种表单组件,一打开就创建了一大堆的 Element 元素。
精确定位,使用了 FinalizationRegistry 类追踪创建的 Dialog 实体,代码如下:
const finalizerRegistry = new FinalizationRegistry((heldValue) => { console.log('Finalizing instance: ',heldValue);});const heldValue = Symbol(`DialogCommandComponent_${Date.now()}`); finalizerRegistry.register(this, heldValue); console.log(`Constructed instance:`,heldValue);
发现一直没有 Constructed instance 销毁的信息输出。
随后,使用了 Edge 浏览器中的分离元素来打快照,步骤如下图。
经过反复的操作,然后点击主动垃圾回收,然后发现 el-dialog 的元素都会增加,基本确认无疑了。
但还是怀疑,会不会是 Dialog 中,引用的问题,导致元素一直没能销毁?所以,使用了纯纯的 el-dialog 来校验,同样的操作,既然如故。
然后的然后,我使用了如下的代码,去校验其它组件是否存在同样的问题。代码如下:
<template><div><el-button @click="fn2">Reset</el-button></div><el-dialog v-model="model" destroy-on-close @closed="fn1" append-to-body v-if="destroyDialogModelValue"></el-dialog><el-button @click="fn0" v-if="!button" primse>Click</el-button><div class="weak" v-if="!button">xxx</div><el-input v-if="!button" /><el-border v-if="!button" /><el-select v-if="!button"><el-option>1111</el-option></el-select><el-switch v-if="!button" /><el-radio v-if="!button" /><el-rate v-if="!button" /><el-slider v-if="!button" /><el-time-picker v-if="!button" /><el-time-select v-if="!button" /><el-transfer v-if="!button" /><el-tree-select v-if="!button" /><el-calendar v-if="!button" /><el-card v-if="!button" /><el-carousel height="150px" v-if="!button"><el-carousel-item v-for="item in 4" :key="item"><h3 class="small justify-center" text="2xl">{{ item }}</h3></el-carousel-item></el-carousel><el-descriptions title="User Info" v-if="!button"><el-descriptions-item label="Username">kooriookami</el-descriptions-item></el-descriptions><el-table style="width: 100%" v-if="!button"><el-table-column prop="date" label="Date" width="180" /><el-table-column prop="name" label="Name" width="180" /><el-table-column prop="address" label="Address" /></el-table><el-avatar v-if="!button" /><el-pagination layout="prev, pager, next" :total="50" v-if="!button" /><el-progress :percentage="50" v-if="!button" /><el-result icon="success" title="Success Tip" sub-title="Please follow the instructions" v-if="!button"><template #extra><el-button type="primary">Back</el-button></template></el-result><el-skeleton v-if="!button" /><el-tag v-if="!button" /><el-timeline v-if="!button" /><el-tree v-if="!button" /><el-avatar v-if="!button" /><el-segmented size="large" v-if="!button" /><el-dropdown v-if="!button"><span class="el-dropdown-link">Dropdown List <el-icon class="el-icon--right"><arrow-down /></el-icon></span><template #dropdown><el-dropdown-menu><el-dropdown-item>Action 1</el-dropdown-item><el-dropdown-item>Action 2</el-dropdown-item><el-dropdown-item>Action 3</el-dropdown-item><el-dropdown-item disabled>Action 4</el-dropdown-item><el-dropdown-item divided>Action 5</el-dropdown-item></el-dropdown-menu></template></el-dropdown><el-menu class="el-menu-demo" mode="horizontal" v-if="!button"><el-menu-item index="1">Processing Center</el-menu-item><el-sub-menu index="2"><template #title>Workspace</template><el-menu-item index="2-1">item one</el-menu-item><el-menu-item index="2-2">item two</el-menu-item><el-menu-item index="2-3">item three</el-menu-item><el-sub-menu index="2-4"><template #title>item four</template><el-menu-item index="2-4-1">item one</el-menu-item><el-menu-item index="2-4-2">item two</el-menu-item><el-menu-item index="2-4-3">item three</el-menu-item></el-sub-menu></el-sub-menu><el-menu-item index="3" disabled>Info</el-menu-item><el-menu-item index="4">Orders</el-menu-item></el-menu><el-steps style="max-width: 600px" active="0" finish-status="success" v-if="!button"><el-step title="Step 1" /><el-step title="Step 2" /><el-step title="Step 3" /></el-steps><el-tabs class="demo-tabs" v-if="!button"><el-tab-pane label="User" name="first">User</el-tab-pane><el-tab-pane label="Config" name="second">Config</el-tab-pane><el-tab-pane label="Role" name="third">Role</el-tab-pane><el-tab-pane label="Task" name="fourth">Task</el-tab-pane></el-tabs><el-alert title="Success alert" type="success" v-if="!button" /><el-drawer title="I am the title" v-if="!button"><span>Hi, there!</span></el-drawer><div v-loading="model" v-if="!button"></div><el-popconfirm confirm-button-text="Yes" cancel-button-text="No" icon-color="#626AEF" title="Are you sure to delete this?" v-if="!button"><template #reference><el-button>Delete</el-button></template></el-popconfirm><el-popover class="box-item" title="Title" content="Top Center prompts info" placement="top" v-if="!button"><template #reference><div>top</div></template></el-popover><el-tooltip class="box-item" effect="dark" content="Top Left prompts info" placement="top-start" v-if="!button"><div>top-start</div></el-tooltip></template>
<script setup>import { ref } from "vue"; import { ElMessage, ElMessageBox, ElNotification } from "element-plus";const model = ref(false); const destroyDialogModelValue = ref(false); const button = ref(false);function fn0() { model.value = true; destroyDialogModelValue.value = true; ElMessage("This is a message."); ElMessageBox.alert("This is a message", "Title"); ElNotification({ title: "Title", message: "This is a reminder", }); } function fn1() { console.log("closed"); destroyDialogModelValue.value = false; button.value = true; } function reset() { model.value = false } </script><style># app { font-family: Avenir, Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: #2c3e50; margin-top: 60px;}</style>
如上代码,进入页面后,点击 click,然后关闭所有的弹窗。然后再次点击 reset 按钮,然后再次点击 click,关闭所有弹窗。如此可以多操作几次。
就发现了开头的组件,都存在内存泄漏问题。
有问题,当然首先看看别人有没有出现过。各种搜索就不说了,大掘金也搜过,在 Element-plus 的 github 仓里的 Issues 中找过,发现的办法基本无用。
以下是自己思考的几条路子:
还是在这里,求助大佬,看以上思路是否有错,然后跪求 orz 解决办法。
自己后续如果解决对应一些问题,会即时和大家分享。
相关文章
中国台湾问题,从来都不是“打不打”的问题,而是何时回归的问题。之所以台湾问题拖到了现在,并不是因为有美国的牵制。最根本的原因,是大陆想要通过和平的手段...
2025-07-27 0
2025年的夏天,第一批靠打拳出圈的“钢铁打工人”已经诞生了!杭州那场机器人格斗赛,我算是看明白了:以前是人揍人,现在是遥控器揍遥控器,而机器人负责在...
2025-07-27 0
Reddit上一位网友发帖讲述了他购买RTX 5090显卡时的离奇遭遇。他在美国圣克拉拉的Micro Center买了一块RTX 5090,拿到手后感...
2025-07-27 0
今天这部纪录片,可以说是与众不同。首先,它成本不高,甚至在整个片子中会时不时看到,抖动的手持摄像机拍摄。其次,它讲述了生态系统是如何一步步成就的,但视...
2025-07-27 0
本内容来源于@什么值得买APP,观点仅代表作者本人 |作者:WittmanARC在过去的数月里,PCI-E 5.0硬盘市场可谓百花齐放:慧荣主控领跑全...
2025-07-27 0
“达芬奇手术机器人”4.0,这台在7月进驻石大一附院的超级手术助手,随着石大一附院泌尿外科主任李强在控制台的操控,机器人系统在实时执行指令的同时,灵活...
2025-07-27 0
微信聊天记录删除怎么恢复?这是一个非常常见的问题,相信很多朋友都有遇到可能不小心删除了一些重要的聊天记录,删除后不知道怎么才能恢复,这个时候会非常着急...
2025-07-27 0
不得不说,国补期间有些笔记本的性价比确实是挺高的。比如ThinkBook 14+ 2025款,作为新笔记本而且是联想Think产品线的机型,平时恐怕都...
2025-07-27 0
发表评论