Skip to content

Commit

Permalink
fix: 修复未使用 @setup 装饰器导致内存泄漏的BUG
Browse files Browse the repository at this point in the history
  • Loading branch information
lzxb committed Jul 19, 2024
1 parent 14b7035 commit 4f64987
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 21 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
## 1.4.3

- fix: memory leak caused by unused `@Setup` decorator
## 1.4.2

- fix: Type failure
Expand Down
4 changes: 2 additions & 2 deletions src/context.ts
Original file line number Diff line number Diff line change
@@ -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,
Expand Down Expand Up @@ -170,7 +170,7 @@ export class Context<T extends {} = {}, E extends DefaultEmit = DefaultEmit> {
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;
Expand Down
46 changes: 30 additions & 16 deletions src/setup-reference.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,39 @@
class SetupReference {
private _count = 0;
public map = new Map<object, number>();
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<object, number>();

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`)
}
}
6 changes: 3 additions & 3 deletions src/setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down Expand Up @@ -68,9 +68,9 @@ function Setup<T extends TargetConstructor>(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));
}
Expand Down

0 comments on commit 4f64987

Please sign in to comment.