Skip to content

Commit 4f64987

Browse files
committed
fix: 修复未使用 @setup 装饰器导致内存泄漏的BUG
1 parent 14b7035 commit 4f64987

File tree

4 files changed

+38
-21
lines changed

4 files changed

+38
-21
lines changed

CHANGELOG.md

+3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
## 1.4.3
2+
3+
- fix: memory leak caused by unused `@Setup` decorator
14
## 1.4.2
25

36
- fix: Type failure

src/context.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { getCurrentInstance, type VueInstance, isVue3 } from './vue';
2-
import { setupReference } from './setup-reference';
2+
import { bindTarget } from './setup-reference';
33
import { TargetName, Target } from './types';
44
import {
55
SETUP_NAME,
@@ -170,7 +170,7 @@ export class Context<T extends {} = {}, E extends DefaultEmit = DefaultEmit> {
170170
const vm = getCurrentInstance();
171171
this.$vm = vm ?? ({ $props: {}, $emit: emit } as any);
172172
this.$emit = this.$vm.$emit.bind(this.$vm) as E;
173-
setupReference.add(this);
173+
bindTarget(this);
174174
}
175175
public get $props() {
176176
return (this.$vm.$props ?? {}) as T;

src/setup-reference.ts

+30-16
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,39 @@
1-
class SetupReference {
2-
private _count = 0;
3-
public map = new Map<object, number>();
4-
public count() {
5-
this._count++;
6-
}
7-
public add(target: object) {
8-
this.map.set(target, this._count);
9-
this._count = 0;
1+
2+
let count = 0;
3+
let isOpen = false;
4+
5+
export function add () {
6+
if (isOpen) {
7+
count = 1;
8+
} else {
9+
isOpen = true;
10+
count++;
1011
}
11-
public reduce(target: object) {
12-
const { map } = this;
13-
let count = map.get(target)!;
12+
}
1413

14+
const weakMap = new WeakMap<object, number>();
15+
16+
export function popTarget(target: object): boolean {
17+
let count = weakMap.get(target);
18+
if (typeof count === 'number') {
1519
count--;
1620
if (count) {
17-
map.set(target, count);
21+
weakMap.set(target, count)
1822
return false;
23+
} else {
24+
weakMap.delete(target);
25+
isOpen = false
26+
return true;
1927
}
20-
map.delete(target);
21-
return true;
2228
}
29+
return false
2330
}
2431

25-
export const setupReference = new SetupReference();
32+
export function bindTarget(target: object) {
33+
if (count > 0) {
34+
weakMap.set(target, count);
35+
count = 0;
36+
} else {
37+
console.warn(`The instance did not use the '@Setup' decorator`)
38+
}
39+
}

src/setup.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import {
1010
import { initComputed } from './computed';
1111
import { getOptions, getSetupOptions } from './options';
1212
import { initDefine } from './define';
13-
import { setupReference } from './setup-reference';
13+
import { add, popTarget } from './setup-reference';
1414
import { getPropertyDescriptors } from './property-descriptors';
1515

1616
export type TargetConstructor = {
@@ -68,9 +68,9 @@ function Setup<T extends TargetConstructor>(Target: T) {
6868
public static [SETUP_PROPERTY_DESCRIPTOR] =
6969
getPropertyDescriptors(Target);
7070
public constructor(...args: any[]) {
71-
setupReference.count();
71+
add();
7272
super(...args);
73-
if (setupReference.reduce(this)) {
73+
if (popTarget(this)) {
7474
// Vue3 needs to return, vue2 does not need to return
7575
return initHook(reactive(this));
7676
}

0 commit comments

Comments
 (0)