Skip to content

Commit 33fa01c

Browse files
committed
perf: reuse deps dirty check results instead of checking this.dirtyLevel again
1 parent 2f36560 commit 33fa01c

File tree

3 files changed

+89
-95
lines changed

3 files changed

+89
-95
lines changed

src/computed.ts

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,18 @@ export class Computed<T = any> implements IComputed {
2727
) { }
2828

2929
get(): T {
30-
let dirtyLevel = this.dirtyLevel;
31-
if (dirtyLevel === DirtyLevels.MaybeDirty) {
32-
Subscriber.resolveMaybeDirty(this);
33-
dirtyLevel = this.dirtyLevel;
34-
}
35-
if (dirtyLevel >= DirtyLevels.Dirty) {
36-
this.update();
30+
const dirtyLevel = this.dirtyLevel;
31+
if (dirtyLevel > DirtyLevels.None) {
32+
if (dirtyLevel === DirtyLevels.Dirty || Subscriber.checkDirty(this.deps!)) {
33+
if (this.update()) {
34+
const subs = this.subs;
35+
if (subs !== undefined) {
36+
Dependency.propagate(subs);
37+
}
38+
}
39+
} else {
40+
this.dirtyLevel = DirtyLevels.None;
41+
}
3742
}
3843
const activeTrackId = System.activeTrackId;
3944
if (activeTrackId !== 0) {
@@ -45,7 +50,7 @@ export class Computed<T = any> implements IComputed {
4550
return this.cachedValue!;
4651
}
4752

48-
update(): void {
53+
update(): boolean {
4954
const prevSub = Subscriber.startTrack(this);
5055
const oldValue = this.cachedValue;
5156
let newValue: T;
@@ -56,10 +61,8 @@ export class Computed<T = any> implements IComputed {
5661
}
5762
if (oldValue !== newValue) {
5863
this.cachedValue = newValue;
59-
const subs = this.subs;
60-
if (subs !== undefined) {
61-
Dependency.propagate(subs);
62-
}
64+
return true;
6365
}
66+
return false;
6467
}
6568
}

src/effect.ts

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -41,20 +41,23 @@ export class Effect<T = any> implements IEffect, Dependency {
4141
let dirtyLevel = this.dirtyLevel;
4242
if (dirtyLevel > DirtyLevels.None) {
4343
if (dirtyLevel === DirtyLevels.MaybeDirty) {
44-
Subscriber.resolveMaybeDirty(this);
45-
dirtyLevel = this.dirtyLevel;
44+
dirtyLevel = Subscriber.checkDirty(this.deps!)
45+
? DirtyLevels.Dirty
46+
: DirtyLevels.SideEffectsOnly;
4647
}
4748
if (dirtyLevel === DirtyLevels.Dirty) {
4849
this.run();
4950
} else {
5051
this.dirtyLevel = DirtyLevels.None;
51-
let link = this.deps;
52-
while (link !== undefined) {
53-
const dep = link.dep;
54-
if ('notify' in dep) {
55-
dep.notify();
52+
if (dirtyLevel === DirtyLevels.SideEffectsOnly) {
53+
let link = this.deps;
54+
while (link !== undefined) {
55+
const dep = link.dep;
56+
if ('notify' in dep) {
57+
dep.notify();
58+
}
59+
link = link.nextDep;
5660
}
57-
link = link.nextDep;
5861
}
5962
}
6063
}

src/system.ts

Lines changed: 63 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ export interface IEffect extends Subscriber {
44
}
55

66
export interface IComputed extends Dependency, Subscriber {
7-
update(): void;
7+
update(): boolean;
88
}
99

1010
export interface Dependency {
@@ -169,7 +169,7 @@ export namespace Dependency {
169169
let link: Link | undefined = subs;
170170
let dep = subs.dep;
171171
let dirtyLevel = DirtyLevels.Dirty;
172-
let remainingQuantity = 0;
172+
let stack = 0;
173173

174174
do {
175175
if (link !== undefined) {
@@ -193,7 +193,7 @@ export namespace Dependency {
193193
} else {
194194
dirtyLevel = DirtyLevels.MaybeDirty;
195195
}
196-
remainingQuantity++;
196+
stack++;
197197

198198
continue;
199199
}
@@ -223,7 +223,7 @@ export namespace Dependency {
223223
} else {
224224
dirtyLevel = DirtyLevels.MaybeDirty;
225225
}
226-
remainingQuantity++;
226+
stack++;
227227

228228
continue;
229229
} else if ('notify' in sub) {
@@ -242,17 +242,17 @@ export namespace Dependency {
242242
continue;
243243
}
244244

245-
if (remainingQuantity !== 0) {
245+
if (stack > 0) {
246246
const depsTail = (dep as IComputed | IEffect).depsTail!;
247247
const prevLink = depsTail.nextDep!;
248248
const prevSub = prevLink.sub;
249249

250250
depsTail.nextDep = undefined;
251251
dep = prevLink.dep;
252252
link = prevLink.nextSub;
253-
remainingQuantity--;
253+
stack--;
254254

255-
if (remainingQuantity === 0) {
255+
if (stack === 0) {
256256
dirtyLevel = DirtyLevels.Dirty;
257257
} else if ('notify' in dep) {
258258
dirtyLevel = DirtyLevels.SideEffectsOnly;
@@ -282,43 +282,41 @@ export namespace Subscriber {
282282

283283
const system = System;
284284

285-
export function resolveMaybeDirty(sub: IComputed | IEffect, depth = 0): void {
286-
let link = sub.deps;
287-
288-
while (link !== undefined) {
285+
export function checkDirty(link: Link, depth = 0): boolean {
286+
do {
289287
const dep = link.dep;
290288
if ('update' in dep) {
291-
let dirtyLevel = dep.dirtyLevel;
292-
293-
if (dirtyLevel === DirtyLevels.MaybeDirty) {
294-
if (depth >= 4) {
295-
resolveMaybeDirtyNonRecursive(dep);
289+
const dirtyLevel = dep.dirtyLevel;
290+
if (dirtyLevel !== DirtyLevels.None) {
291+
if (
292+
dirtyLevel === DirtyLevels.Dirty
293+
|| (
294+
depth < 4
295+
? checkDirty(dep.deps!, depth + 1)
296+
: checkDirtyNonRecursive(dep)
297+
)
298+
) {
299+
if (dep.update()) {
300+
Dependency.propagate(dep.subs!);
301+
return true;
302+
}
296303
} else {
297-
resolveMaybeDirty(dep, depth + 1);
298-
}
299-
dirtyLevel = dep.dirtyLevel;
300-
}
301-
if (dirtyLevel === DirtyLevels.Dirty) {
302-
dep.update();
303-
if (sub.dirtyLevel === DirtyLevels.Dirty) {
304-
break;
304+
dep.dirtyLevel = DirtyLevels.None;
305305
}
306306
}
307307
}
308-
link = link.nextDep;
309-
}
310-
311-
if (sub.dirtyLevel === DirtyLevels.MaybeDirty) {
312-
sub.dirtyLevel = DirtyLevels.None;
313-
}
308+
link = link.nextDep!;
309+
} while (link !== undefined);
310+
return false;
314311
}
315312

316-
export function resolveMaybeDirtyNonRecursive(sub: IComputed | IEffect): void {
317-
let link = sub.deps;
318-
let remaining = 0;
313+
function checkDirtyNonRecursive(sub: Link['sub']): boolean {
314+
let subDirtyLevel = DirtyLevels.MaybeDirty;
315+
let link = sub.deps!;
316+
let stack = 0;
319317

320318
do {
321-
if (link !== undefined) {
319+
if (subDirtyLevel === DirtyLevels.MaybeDirty) {
322320
const dep = link.dep;
323321

324322
if ('update' in dep) {
@@ -327,61 +325,51 @@ export namespace Subscriber {
327325
if (depDirtyLevel === DirtyLevels.MaybeDirty) {
328326
dep.subs!.prevSub = link;
329327
sub = dep;
330-
link = dep.deps;
331-
remaining++;
332-
328+
link = dep.deps!;
329+
stack++;
333330
continue;
334-
} else if (depDirtyLevel === DirtyLevels.Dirty) {
335-
dep.update();
336-
337-
if (sub.dirtyLevel === DirtyLevels.Dirty) {
338-
if (remaining !== 0) {
339-
const subSubs = (sub as IComputed).subs!;
340-
const prevLink = subSubs.prevSub!;
341-
(sub as IComputed).update();
342-
subSubs.prevSub = undefined;
343-
sub = prevLink.sub as IComputed | IEffect;
344-
link = prevLink.nextDep;
345-
remaining--;
346-
continue;
347-
}
348-
349-
break;
331+
}
332+
if (depDirtyLevel === DirtyLevels.Dirty) {
333+
if (dep.update()) {
334+
Dependency.propagate(dep.subs!);
335+
subDirtyLevel = DirtyLevels.Dirty;
336+
continue;
350337
}
351338
}
352339
}
353340

354-
link = link.nextDep;
341+
link = link.nextDep!;
342+
if (link === undefined) {
343+
subDirtyLevel = DirtyLevels.None;
344+
}
355345
continue;
356346
}
357347

358-
const dirtyLevel = sub.dirtyLevel;
359-
360-
if (dirtyLevel === DirtyLevels.MaybeDirty) {
361-
sub.dirtyLevel = DirtyLevels.None;
362-
if (remaining !== 0) {
363-
const subSubs = (sub as IComputed).subs!;
364-
const prevLink = subSubs.prevSub!;
365-
subSubs.prevSub = undefined;
366-
sub = prevLink.sub as IComputed | IEffect;
367-
link = prevLink.nextDep;
368-
remaining--;
369-
continue;
370-
}
371-
} else if (remaining !== 0) {
372-
if (dirtyLevel === DirtyLevels.Dirty) {
373-
(sub as IComputed).update();
374-
}
348+
if (stack > 0) {
349+
stack--;
375350
const subSubs = (sub as IComputed).subs!;
376351
const prevLink = subSubs.prevSub!;
377352
subSubs.prevSub = undefined;
378-
sub = prevLink.sub as IComputed | IEffect;
379-
link = prevLink.nextDep;
380-
remaining--;
353+
if (subDirtyLevel === DirtyLevels.Dirty) {
354+
if ((sub as IComputed).update()) {
355+
Dependency.propagate(subSubs);
356+
sub = prevLink.sub;
357+
continue;
358+
}
359+
} else {
360+
sub.dirtyLevel = DirtyLevels.None;
361+
}
362+
link = prevLink.nextDep!;
363+
sub = prevLink.sub;
364+
if (link !== undefined) {
365+
subDirtyLevel = DirtyLevels.MaybeDirty;
366+
} else {
367+
subDirtyLevel = DirtyLevels.None;
368+
}
381369
continue;
382370
}
383371

384-
break;
372+
return subDirtyLevel === DirtyLevels.Dirty;
385373
} while (true);
386374
}
387375

0 commit comments

Comments
 (0)