From 4f6498735f18a6baeb0f83763e4882be4594b1ad Mon Sep 17 00:00:00 2001 From: lzxb <1340641314@qq.com> Date: Fri, 19 Jul 2024 14:35:42 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E6=9C=AA=E4=BD=BF?= =?UTF-8?q?=E7=94=A8=20@Setup=20=E8=A3=85=E9=A5=B0=E5=99=A8=E5=AF=BC?= =?UTF-8?q?=E8=87=B4=E5=86=85=E5=AD=98=E6=B3=84=E6=BC=8F=E7=9A=84BUG?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 3 +++ src/context.ts | 4 ++-- src/setup-reference.ts | 46 +++++++++++++++++++++++++++--------------- src/setup.ts | 6 +++--- 4 files changed, 38 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 20ce987..a2c4c3b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +## 1.4.3 + +- fix: memory leak caused by unused `@Setup` decorator ## 1.4.2 - fix: Type failure diff --git a/src/context.ts b/src/context.ts index 0cef07b..0717f06 100644 --- a/src/context.ts +++ b/src/context.ts @@ -1,5 +1,5 @@ import { getCurrentInstance, type VueInstance, isVue3 } from './vue'; -import { setupReference } from './setup-reference'; +import { bindTarget } from './setup-reference'; import { TargetName, Target } from './types'; import { SETUP_NAME, @@ -170,7 +170,7 @@ export class Context { const vm = getCurrentInstance(); this.$vm = vm ?? ({ $props: {}, $emit: emit } as any); this.$emit = this.$vm.$emit.bind(this.$vm) as E; - setupReference.add(this); + bindTarget(this); } public get $props() { return (this.$vm.$props ?? {}) as T; diff --git a/src/setup-reference.ts b/src/setup-reference.ts index 03a671f..977a64f 100644 --- a/src/setup-reference.ts +++ b/src/setup-reference.ts @@ -1,25 +1,39 @@ -class SetupReference { - private _count = 0; - public map = new Map(); - public count() { - this._count++; - } - public add(target: object) { - this.map.set(target, this._count); - this._count = 0; + +let count = 0; +let isOpen = false; + +export function add () { + if (isOpen) { + count = 1; + } else { + isOpen = true; + count++; } - public reduce(target: object) { - const { map } = this; - let count = map.get(target)!; +} +const weakMap = new WeakMap(); + +export function popTarget(target: object): boolean { + let count = weakMap.get(target); + if (typeof count === 'number') { count--; if (count) { - map.set(target, count); + weakMap.set(target, count) return false; + } else { + weakMap.delete(target); + isOpen = false + return true; } - map.delete(target); - return true; } + return false } -export const setupReference = new SetupReference(); +export function bindTarget(target: object) { + if (count > 0) { + weakMap.set(target, count); + count = 0; + } else { + console.warn(`The instance did not use the '@Setup' decorator`) + } +} diff --git a/src/setup.ts b/src/setup.ts index a91bdd1..b85c2ac 100644 --- a/src/setup.ts +++ b/src/setup.ts @@ -10,7 +10,7 @@ import { import { initComputed } from './computed'; import { getOptions, getSetupOptions } from './options'; import { initDefine } from './define'; -import { setupReference } from './setup-reference'; +import { add, popTarget } from './setup-reference'; import { getPropertyDescriptors } from './property-descriptors'; export type TargetConstructor = { @@ -68,9 +68,9 @@ function Setup(Target: T) { public static [SETUP_PROPERTY_DESCRIPTOR] = getPropertyDescriptors(Target); public constructor(...args: any[]) { - setupReference.count(); + add(); super(...args); - if (setupReference.reduce(this)) { + if (popTarget(this)) { // Vue3 needs to return, vue2 does not need to return return initHook(reactive(this)); }