Skip to content

Commit

Permalink
perf(common): AsyncPipe should not call markForCheck on subscript…
Browse files Browse the repository at this point in the history
…ion (#54554)

This commit prevents `AsyncPipe` from calling `markForCheck` when values
are synchronously emit during subscription to an observable. This
prevents subscriptions to `Replay` observables from needlessly walking
up to the root of the view tree during template execution for each
new replay observable in the template.

PR Close #54554
  • Loading branch information
atscott authored and dylhunn committed Feb 23, 2024
1 parent 600a8cd commit 1a526f2
Showing 1 changed file with 13 additions and 4 deletions.
17 changes: 13 additions & 4 deletions packages/common/src/pipes/async_pipe.ts
Expand Up @@ -102,6 +102,7 @@ const _subscribableStrategy = new SubscribableStrategy();
export class AsyncPipe implements OnDestroy, PipeTransform {
private _ref: ChangeDetectorRef | null;
private _latestValue: any = null;
private markForCheckOnValueUpdate = true;

private _subscription: Unsubscribable | Promise<any> | null = null;
private _obj: Subscribable<any> | Promise<any> | EventEmitter<any> | null = null;
Expand Down Expand Up @@ -134,7 +135,15 @@ export class AsyncPipe implements OnDestroy, PipeTransform {
transform<T>(obj: Observable<T> | Subscribable<T> | Promise<T> | null | undefined): T | null {
if (!this._obj) {
if (obj) {
this._subscribe(obj);
try {
// Only call `markForCheck` if the value is updated asynchronously.
// Synchronous updates _during_ subscription should not wastefully mark for check -
// this value is already going to be returned from the transform function.
this.markForCheckOnValueUpdate = false;
this._subscribe(obj);
} finally {
this.markForCheckOnValueUpdate = true;
}
}
return this._latestValue;
}
Expand Down Expand Up @@ -181,9 +190,9 @@ export class AsyncPipe implements OnDestroy, PipeTransform {
private _updateLatestValue(async: any, value: Object): void {
if (async === this._obj) {
this._latestValue = value;
// Note: `this._ref` is only cleared in `ngOnDestroy` so is known to be available when a
// value is being updated.
this._ref!.markForCheck();
if (this.markForCheckOnValueUpdate) {
this._ref?.markForCheck();
}
}
}
}

0 comments on commit 1a526f2

Please sign in to comment.