From 2e472c5e5e559a7a4083b4164ffe0c3911ce0651 Mon Sep 17 00:00:00 2001 From: Matt Lavallee Date: Fri, 30 Nov 2018 17:36:08 -0500 Subject: [PATCH] fix(component): clean up memory leak after loading async component completes (fix #8740) (#8755) * fix(component): clean up memory leak after loading async component completes * fix(async component): accounting for async components with loading property * refactor(component): simplifying memory cleanup logic --- src/core/vdom/helpers/resolve-async-component.js | 12 ++++++++---- .../unit/features/transition/transition-mode.spec.js | 2 +- test/unit/modules/vdom/create-component.spec.js | 2 ++ 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/core/vdom/helpers/resolve-async-component.js b/src/core/vdom/helpers/resolve-async-component.js index 99ce5ce47e..44ca238854 100644 --- a/src/core/vdom/helpers/resolve-async-component.js +++ b/src/core/vdom/helpers/resolve-async-component.js @@ -61,10 +61,14 @@ export function resolveAsyncComponent ( const contexts = factory.contexts = [context] let sync = true - const forceRender = () => { + const forceRender = (renderCompleted: boolean) => { for (let i = 0, l = contexts.length; i < l; i++) { contexts[i].$forceUpdate() } + + if (renderCompleted) { + contexts.length = 0 + } } const resolve = once((res: Object | Class) => { @@ -73,7 +77,7 @@ export function resolveAsyncComponent ( // invoke callbacks only if this is not a synchronous resolve // (async resolves are shimmed as synchronous during SSR) if (!sync) { - forceRender() + forceRender(true) } }) @@ -84,7 +88,7 @@ export function resolveAsyncComponent ( ) if (isDef(factory.errorComp)) { factory.error = true - forceRender() + forceRender(true) } }) @@ -111,7 +115,7 @@ export function resolveAsyncComponent ( setTimeout(() => { if (isUndef(factory.resolved) && isUndef(factory.error)) { factory.loading = true - forceRender() + forceRender(false) } }, res.delay || 200) } diff --git a/test/unit/features/transition/transition-mode.spec.js b/test/unit/features/transition/transition-mode.spec.js index 6e4f5be06c..f8afca82f5 100644 --- a/test/unit/features/transition/transition-mode.spec.js +++ b/test/unit/features/transition/transition-mode.spec.js @@ -457,7 +457,7 @@ if (!isIE9) { setTimeout(() => { resolve({ template: '

component B

' }) Vue.nextTick(next) - }, (duration + buffer) * 1.5) + }, (duration + buffer) * 1.7) } }, data: { diff --git a/test/unit/modules/vdom/create-component.spec.js b/test/unit/modules/vdom/create-component.spec.js index db0c59e374..e69fca0eff 100644 --- a/test/unit/modules/vdom/create-component.spec.js +++ b/test/unit/modules/vdom/create-component.spec.js @@ -58,6 +58,7 @@ describe('create-component', () => { vnode = createComponent(async, data, vm, vm) expect(vnode.isComment).toBe(true) // not to be loaded yet. expect(vnode.asyncFactory).toBe(async) + expect(vnode.asyncFactory.contexts.length).toEqual(1) } function loaded () { vnode = createComponent(async, data, vm, vm) @@ -68,6 +69,7 @@ describe('create-component', () => { expect(vnode.elm).toBeUndefined() expect(vnode.ns).toBeUndefined() expect(vnode.context).toEqual(vm) + expect(vnode.asyncFactory.contexts.length).toEqual(0) expect(vm.$forceUpdate).toHaveBeenCalled() done() }