环境信息
- micro-app:1.0.0-rc.31
- 基座应用:Vue 3 + Vite
- 子应用:Vue 3 + Vite
- 沙箱模式:iframe
- 浏览器:基于 Chromium 的 Edge / Chrome
问题描述
在多个子应用之间反复切换并卸载子应用后,即使子应用已经销毁,浏览器内存和事件监听器数量仍然持续增长。
我们的基座确实调用了 microApp.unmountApp(name, { destroy: true }),子应用 Vue 实例的 unmount 生命周期也会执行,iframe 节点也会被移除。但绑定在基座 document 上的部分事件监听器仍然存在,并继续持有旧子应用的 DOM 和 Vue 对象。
复现步骤
- 使用 Vue 3 + Vite 基座,开启 iframe 沙箱和
keep-alive="true"。
- 打开一个会注册 document/window 事件的子应用,例如
click、scroll。
- 切换到另一个子应用。
- 调用
microApp.unmountApp(childName, { destroy: true })。
- 重复上述步骤多次。
- 强制 GC 后检查
Memory.getDOMCounters() 和 document 事件监听器。
在我们的生产规模应用中,每次循环大约残留 5,300 个 DOM 节点和 2,500 个事件监听器。循环 6 次后,即使强制 GC,JavaScript 堆仍增加了 100 MB 以上。
初步定位
沙箱效果清理逻辑注册监听器时传入了 options 对象,其中可能包含 capture: true,但清理时没有传入相同的 capture 值。例如:
rawAddEventListener.call(target, type, handler, options)
rawRemoveEventListener.call(target, type, handler)
建议清理时传回原始监听器配置:
rawRemoveEventListener.call(target, type, handler, listener.__MICRO_APP_MARK_OPTIONS__)
我们在 createProxyDocument、patchWindowEffect、patchWindowEffect$1 和 patchDocumentEffect 四处清理逻辑中应用了这个修改。修改后,重复卸载和重新加载 6 次,DOM 节点稳定在 14,800 个,事件监听器稳定在 3,166 个。
相关 Issue
这个问题可能与 #1017、#1030、#1691 有关,但本 Issue 提供了具体的监听器残留复现数据和疑似修复方案。
请维护者确认这个清理行为是否符合预期,并考虑在后续版本中修复。
环境信息
问题描述
在多个子应用之间反复切换并卸载子应用后,即使子应用已经销毁,浏览器内存和事件监听器数量仍然持续增长。
我们的基座确实调用了
microApp.unmountApp(name, { destroy: true }),子应用 Vue 实例的unmount生命周期也会执行,iframe 节点也会被移除。但绑定在基座 document 上的部分事件监听器仍然存在,并继续持有旧子应用的 DOM 和 Vue 对象。复现步骤
keep-alive="true"。click、scroll。microApp.unmountApp(childName, { destroy: true })。Memory.getDOMCounters()和 document 事件监听器。在我们的生产规模应用中,每次循环大约残留 5,300 个 DOM 节点和 2,500 个事件监听器。循环 6 次后,即使强制 GC,JavaScript 堆仍增加了 100 MB 以上。
初步定位
沙箱效果清理逻辑注册监听器时传入了 options 对象,其中可能包含
capture: true,但清理时没有传入相同的 capture 值。例如:建议清理时传回原始监听器配置:
我们在
createProxyDocument、patchWindowEffect、patchWindowEffect$1和patchDocumentEffect四处清理逻辑中应用了这个修改。修改后,重复卸载和重新加载 6 次,DOM 节点稳定在 14,800 个,事件监听器稳定在 3,166 个。相关 Issue
这个问题可能与 #1017、#1030、#1691 有关,但本 Issue 提供了具体的监听器残留复现数据和疑似修复方案。
请维护者确认这个清理行为是否符合预期,并考虑在后续版本中修复。