From 7d4c56818c77e4d80e8f0706fc7db9857c660b84 Mon Sep 17 00:00:00 2001 From: Gcaufy Date: Sat, 7 May 2022 15:27:02 +0800 Subject: [PATCH] fix(core): fix GC problem during page navigation, for some reason the page and component instance is not released re #2712 --- packages/core/weapp/class/Base.js | 1 + packages/core/weapp/class/WepyComponent.js | 29 ++++++++++++++++++++++ packages/core/weapp/init/lifecycle.js | 20 +++++++-------- 3 files changed, 40 insertions(+), 10 deletions(-) diff --git a/packages/core/weapp/class/Base.js b/packages/core/weapp/class/Base.js index 8a99fa0e1..c37c928c3 100644 --- a/packages/core/weapp/class/Base.js +++ b/packages/core/weapp/class/Base.js @@ -5,6 +5,7 @@ export default class Base { constructor() { this._events = {}; this._watchers = []; + this.$children = []; } $set(target, key, val) { diff --git a/packages/core/weapp/class/WepyComponent.js b/packages/core/weapp/class/WepyComponent.js index 21034f77f..c4559946f 100644 --- a/packages/core/weapp/class/WepyComponent.js +++ b/packages/core/weapp/class/WepyComponent.js @@ -3,8 +3,16 @@ import Watcher from '../observer/watcher'; import { isArr, isPlainObject } from '../../shared/index'; import { renderNextTick } from '../util/next-tick'; +import Dirty from './Dirty'; export default class WepyComponent extends Base { + + constructor() { + super(); + this.$children = []; + this.$dirty = new Dirty('path'); + this.$refs = {}; + } $watch(expOrFn, cb, options) { let vm = this; if (isArr(cb)) { @@ -52,6 +60,27 @@ export default class WepyComponent extends Base { $trigger(event, data, option) { this.$wx.triggerEvent(event, { arguments: [data] }, option); } + + $destroy() { + this.$children.forEach(child => { + if (!child._detached) { + child.$destroy(); + } + }); + this._watcher.cleanupDeps(); + this._watcher.teardown(); + this._watchers.forEach(item => { + item.cleanupDeps(); + item.teardown(); + }); + this._watchers = []; + this._events = {}; + this._detached = true; + delete this._data.__ob__; + delete this._data; + delete this._watcher; + delete this.$root; + } } WepyComponent.prototype.$nextTick = renderNextTick; diff --git a/packages/core/weapp/init/lifecycle.js b/packages/core/weapp/init/lifecycle.js index be7130413..b3b593ac6 100644 --- a/packages/core/weapp/init/lifecycle.js +++ b/packages/core/weapp/init/lifecycle.js @@ -9,7 +9,6 @@ import { initData } from './data'; import { initComputed } from './computed'; import { initMethods } from './methods'; import { isArr, isFunc } from '../../shared/index'; -import Dirty from '../class/Dirty'; import { WEAPP_APP_LIFECYCLE, WEAPP_PAGE_LIFECYCLE, @@ -36,7 +35,7 @@ const callUserMethod = function(vm, userOpt, method, args) { return result; }; -const getLifecycycle = (defaultLifecycle, rel, type) => { +const getLifecycle = (defaultLifecycle, rel, type) => { let lifecycle = defaultLifecycle.concat([]); if (rel && rel.lifecycle && rel.lifecycle[type]) { let userDefinedLifecycle = []; @@ -75,7 +74,7 @@ export function patchAppLifecycle(appConfig, options, rel = {}) { return callUserMethod(vm, vm.$options, 'onLaunch', args); }; - let lifecycle = getLifecycycle(WEAPP_APP_LIFECYCLE, rel, 'app'); + let lifecycle = getLifecycle(WEAPP_APP_LIFECYCLE, rel, 'app'); lifecycle.forEach(k => { // it's not defined aready && user defined it && it's an array or function @@ -92,10 +91,6 @@ export function patchLifecycle(output, options, rel, isComponent) { const initLifecycle = function(...args) { let vm = new initClass(); - vm.$dirty = new Dirty('path'); - vm.$children = []; - vm.$refs = {}; - this.$wepy = vm; vm.$wx = this; vm.$is = this.is; @@ -165,7 +160,7 @@ export function patchLifecycle(output, options, rel, isComponent) { // 增加组件页面声明周期 output.pageLifetimes = {}; - const lifecycle = getLifecycycle(WEAPP_COMPONENT_PAGE_LIFECYCLE, rel, 'component'); + const lifecycle = getLifecycle(WEAPP_COMPONENT_PAGE_LIFECYCLE, rel, 'component'); lifecycle.forEach(function(k) { if (!output.pageLifetimes[k] && options[k] && (isFunc(options[k]) || isArr(options[k]))) { @@ -245,7 +240,7 @@ export function patchLifecycle(output, options, rel, isComponent) { // } // }) - let lifecycle = getLifecycycle(WEAPP_PAGE_LIFECYCLE, rel, 'page'); + let lifecycle = getLifecycle(WEAPP_PAGE_LIFECYCLE, rel, 'page'); lifecycle.forEach(k => { if (!output[k] && options[k] && (isFunc(options[k]) || isArr(options[k]))) { @@ -255,7 +250,12 @@ export function patchLifecycle(output, options, rel, isComponent) { } }); } - let lifecycle = getLifecycycle(WEAPP_COMPONENT_LIFECYCLE, rel, 'component'); + output.detached = function(...args) { + let vm = this.$wepy; + vm.destroy(); + return callUserMethod(vm, vm.$options, 'detached', args); + } + let lifecycle = getLifecycle(WEAPP_COMPONENT_LIFECYCLE, rel, 'component'); lifecycle.forEach(k => { // beforeCreate is not a real lifecycle