From 00ddb5be0e6a51c3c3122578b893ebec0a1f15fa Mon Sep 17 00:00:00 2001 From: Zihao Wu <1248951273@qq.com> Date: Fri, 27 Jun 2025 20:12:27 +0800 Subject: [PATCH 1/4] effectScope scopes doubly-linked list --- packages/reactivity/src/effectScope.ts | 52 +++++++++++++------------- 1 file changed, 25 insertions(+), 27 deletions(-) diff --git a/packages/reactivity/src/effectScope.ts b/packages/reactivity/src/effectScope.ts index 92ad92c1249..70b7613179b 100644 --- a/packages/reactivity/src/effectScope.ts +++ b/packages/reactivity/src/effectScope.ts @@ -32,21 +32,25 @@ export class EffectScope { * record undetached scopes * @internal */ - scopes: EffectScope[] | undefined + scopes: EffectScope | undefined + scopesTail: EffectScope | undefined /** - * track a child scope's index in its parent's scopes array for optimized - * removal - * @internal + * sibling scope */ - private index: number | undefined + prevEffectScope: EffectScope | undefined + nextEffectScope: EffectScope | undefined + constructor(public detached = false) { this.parent = activeEffectScope if (!detached && activeEffectScope) { - this.index = - (activeEffectScope.scopes || (activeEffectScope.scopes = [])).push( - this, - ) - 1 + if(activeEffectScope.scopesTail) { + this.prevEffectScope = activeEffectScope.scopesTail; + activeEffectScope.scopesTail.nextEffectScope = this; + activeEffectScope.scopesTail = this; + }else { + activeEffectScope.scopes = activeEffectScope.scopesTail = this; + } } } @@ -58,10 +62,8 @@ export class EffectScope { if (this._active) { this._isPaused = true let i, l - if (this.scopes) { - for (i = 0, l = this.scopes.length; i < l; i++) { - this.scopes[i].pause() - } + for(let child = this.scopes; child != undefined; child = child.nextEffectScope) { + child.pause(); } for (i = 0, l = this.effects.length; i < l; i++) { this.effects[i].pause() @@ -77,10 +79,8 @@ export class EffectScope { if (this._isPaused) { this._isPaused = false let i, l - if (this.scopes) { - for (i = 0, l = this.scopes.length; i < l; i++) { - this.scopes[i].resume() - } + for(let child = this.scopes; child != undefined; child = child.nextEffectScope) { + child.resume(); } for (i = 0, l = this.effects.length; i < l; i++) { this.effects[i].resume() @@ -140,20 +140,18 @@ export class EffectScope { } this.cleanups.length = 0 - if (this.scopes) { - for (i = 0, l = this.scopes.length; i < l; i++) { - this.scopes[i].stop(true) - } - this.scopes.length = 0 + for(let child = this.scopes; child != undefined; child = child.nextEffectScope) { + child.stop(); } + this.scopes = this.scopesTail = undefined; // nested scope, dereference from parent to avoid memory leaks if (!this.detached && this.parent && !fromParent) { - // optimized O(1) removal - const last = this.parent.scopes!.pop() - if (last && last !== this) { - this.parent.scopes![this.index!] = last - last.index = this.index! + if(this.parent.scopes == this) { + this.parent.scopes = this.nextEffectScope; + } + if(this.parent.scopesTail == this) { + this.parent.scopesTail = this.prevEffectScope; } } this.parent = undefined From a0b78f6322d58b9d77d47d0fd3960559283126b9 Mon Sep 17 00:00:00 2001 From: Zihao Wu <1248951273@qq.com> Date: Fri, 27 Jun 2025 20:45:43 +0800 Subject: [PATCH 2/4] effectScope scopes doubly-linked list --- packages/reactivity/src/effectScope.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/reactivity/src/effectScope.ts b/packages/reactivity/src/effectScope.ts index 70b7613179b..279c7caba1b 100644 --- a/packages/reactivity/src/effectScope.ts +++ b/packages/reactivity/src/effectScope.ts @@ -147,6 +147,12 @@ export class EffectScope { // nested scope, dereference from parent to avoid memory leaks if (!this.detached && this.parent && !fromParent) { + if(this.prevEffectScope) { + this.prevEffectScope.nextEffectScope = this.nextEffectScope; + } + if(this.nextEffectScope) { + this.nextEffectScope.prevEffectScope = this.prevEffectScope; + } if(this.parent.scopes == this) { this.parent.scopes = this.nextEffectScope; } From 1f63cf607f382652554ff15a0ac3c87863486628 Mon Sep 17 00:00:00 2001 From: Zihao Wu <1248951273@qq.com> Date: Fri, 27 Jun 2025 21:05:55 +0800 Subject: [PATCH 3/4] effectScope scopes doubly-linked list --- packages/reactivity/src/effectScope.ts | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/packages/reactivity/src/effectScope.ts b/packages/reactivity/src/effectScope.ts index 279c7caba1b..fe2ed183d91 100644 --- a/packages/reactivity/src/effectScope.ts +++ b/packages/reactivity/src/effectScope.ts @@ -44,11 +44,11 @@ export class EffectScope { constructor(public detached = false) { this.parent = activeEffectScope if (!detached && activeEffectScope) { - if(activeEffectScope.scopesTail) { + if (activeEffectScope.scopesTail) { this.prevEffectScope = activeEffectScope.scopesTail; activeEffectScope.scopesTail.nextEffectScope = this; activeEffectScope.scopesTail = this; - }else { + } else { activeEffectScope.scopes = activeEffectScope.scopesTail = this; } } @@ -61,11 +61,10 @@ export class EffectScope { pause(): void { if (this._active) { this._isPaused = true - let i, l - for(let child = this.scopes; child != undefined; child = child.nextEffectScope) { + for (let child = this.scopes; child != undefined; child = child.nextEffectScope) { child.pause(); } - for (i = 0, l = this.effects.length; i < l; i++) { + for (let i = 0, l = this.effects.length; i < l; i++) { this.effects[i].pause() } } @@ -78,11 +77,10 @@ export class EffectScope { if (this._active) { if (this._isPaused) { this._isPaused = false - let i, l - for(let child = this.scopes; child != undefined; child = child.nextEffectScope) { + for (let child = this.scopes; child != undefined; child = child.nextEffectScope) { child.resume(); } - for (i = 0, l = this.effects.length; i < l; i++) { + for (let i = 0, l = this.effects.length; i < l; i++) { this.effects[i].resume() } } @@ -140,23 +138,23 @@ export class EffectScope { } this.cleanups.length = 0 - for(let child = this.scopes; child != undefined; child = child.nextEffectScope) { - child.stop(); + for (let child = this.scopes; child != undefined; child = child.nextEffectScope) { + child.stop(true); } this.scopes = this.scopesTail = undefined; // nested scope, dereference from parent to avoid memory leaks if (!this.detached && this.parent && !fromParent) { - if(this.prevEffectScope) { + if (this.prevEffectScope) { this.prevEffectScope.nextEffectScope = this.nextEffectScope; } - if(this.nextEffectScope) { + if (this.nextEffectScope) { this.nextEffectScope.prevEffectScope = this.prevEffectScope; } - if(this.parent.scopes == this) { + if (this.parent.scopes == this) { this.parent.scopes = this.nextEffectScope; } - if(this.parent.scopesTail == this) { + if (this.parent.scopesTail == this) { this.parent.scopesTail = this.prevEffectScope; } } From 001a1e6495490f0d15b8340fdb99b2db488322d5 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Fri, 27 Jun 2025 14:10:03 +0000 Subject: [PATCH 4/4] [autofix.ci] apply automated fixes --- packages/reactivity/src/effectScope.ts | 43 ++++++++++++++++---------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/packages/reactivity/src/effectScope.ts b/packages/reactivity/src/effectScope.ts index fe2ed183d91..4b6c0b7c6a4 100644 --- a/packages/reactivity/src/effectScope.ts +++ b/packages/reactivity/src/effectScope.ts @@ -40,16 +40,15 @@ export class EffectScope { prevEffectScope: EffectScope | undefined nextEffectScope: EffectScope | undefined - constructor(public detached = false) { this.parent = activeEffectScope if (!detached && activeEffectScope) { if (activeEffectScope.scopesTail) { - this.prevEffectScope = activeEffectScope.scopesTail; - activeEffectScope.scopesTail.nextEffectScope = this; - activeEffectScope.scopesTail = this; + this.prevEffectScope = activeEffectScope.scopesTail + activeEffectScope.scopesTail.nextEffectScope = this + activeEffectScope.scopesTail = this } else { - activeEffectScope.scopes = activeEffectScope.scopesTail = this; + activeEffectScope.scopes = activeEffectScope.scopesTail = this } } } @@ -61,8 +60,12 @@ export class EffectScope { pause(): void { if (this._active) { this._isPaused = true - for (let child = this.scopes; child != undefined; child = child.nextEffectScope) { - child.pause(); + for ( + let child = this.scopes; + child != undefined; + child = child.nextEffectScope + ) { + child.pause() } for (let i = 0, l = this.effects.length; i < l; i++) { this.effects[i].pause() @@ -77,8 +80,12 @@ export class EffectScope { if (this._active) { if (this._isPaused) { this._isPaused = false - for (let child = this.scopes; child != undefined; child = child.nextEffectScope) { - child.resume(); + for ( + let child = this.scopes; + child != undefined; + child = child.nextEffectScope + ) { + child.resume() } for (let i = 0, l = this.effects.length; i < l; i++) { this.effects[i].resume() @@ -138,24 +145,28 @@ export class EffectScope { } this.cleanups.length = 0 - for (let child = this.scopes; child != undefined; child = child.nextEffectScope) { - child.stop(true); + for ( + let child = this.scopes; + child != undefined; + child = child.nextEffectScope + ) { + child.stop(true) } - this.scopes = this.scopesTail = undefined; + this.scopes = this.scopesTail = undefined // nested scope, dereference from parent to avoid memory leaks if (!this.detached && this.parent && !fromParent) { if (this.prevEffectScope) { - this.prevEffectScope.nextEffectScope = this.nextEffectScope; + this.prevEffectScope.nextEffectScope = this.nextEffectScope } if (this.nextEffectScope) { - this.nextEffectScope.prevEffectScope = this.prevEffectScope; + this.nextEffectScope.prevEffectScope = this.prevEffectScope } if (this.parent.scopes == this) { - this.parent.scopes = this.nextEffectScope; + this.parent.scopes = this.nextEffectScope } if (this.parent.scopesTail == this) { - this.parent.scopesTail = this.prevEffectScope; + this.parent.scopesTail = this.prevEffectScope } } this.parent = undefined