Skip to content
This repository was archived by the owner on Jan 27, 2022. It is now read-only.

Commit eff8b46

Browse files
committed
fix: handle ngFor and ngIf contexts in the profiler
Currently, we skip the time spent in evaluation of embedded view templates because the passed context is either an NgIf or an NgForOf. This change generalizes the implementation to work with views embedded into a component.
1 parent f1b5847 commit eff8b46

File tree

2 files changed

+39
-12
lines changed

2 files changed

+39
-12
lines changed

projects/ng-devtools-backend/src/lib/hooks/capture.ts

+4-3
Original file line numberDiff line numberDiff line change
@@ -31,20 +31,20 @@ export const stop = (): ProfilerFrame => {
3131
return result;
3232
};
3333

34-
const startEvent = (map: { [key: string]: number }, directive: any, label: string) => {
34+
const startEvent = (map: Record<string, number>, directive: any, label: string) => {
3535
const name = getDirectiveName(directive);
3636
const key = `${name}#${label}`;
3737
map[key] = performance.now();
3838
};
3939

40-
const getEventStart = (map: { [key: string]: number }, directive: any, label: string) => {
40+
const getEventStart = (map: Record<string, number>, directive: any, label: string) => {
4141
const name = getDirectiveName(directive);
4242
const key = `${name}#${label}`;
4343
return map[key];
4444
};
4545

4646
const getHooks = (onFrame: (frame: ProfilerFrame) => void): Partial<Hooks> => {
47-
const timeStartMap: { [key: string]: number } = {};
47+
const timeStartMap: Record<string, number> = {};
4848
return {
4949
// We flush here because it's possible the current node to overwrite
5050
// an existing removed node.
@@ -82,6 +82,7 @@ const getHooks = (onFrame: (frame: ProfilerFrame) => void): Partial<Hooks> => {
8282
},
8383
onChangeDetectionEnd(component: any): void {
8484
const profile = eventMap.get(component);
85+
8586
if (profile) {
8687
let current = profile.changeDetection;
8788
if (current === undefined) {

projects/ng-devtools-backend/src/lib/hooks/profiler/native.ts

+35-9
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ type ProfilerCallback = (event: ɵProfilerEvent, instanceOrLView: {}, hookOrList
1010
export class NgProfiler extends Profiler {
1111
private _tracker = IdentityTracker.getInstance();
1212
private _callbacks: ProfilerCallback[] = [];
13+
private _lastDirectiveInstance: {} | null = null;
1314

1415
constructor(config: Partial<Hooks> = {}) {
1516
super(config);
@@ -66,7 +67,7 @@ export class NgProfiler extends Profiler {
6667
return;
6768
}
6869

69-
[ɵProfilerEvent.TemplateUpdateStart](directive: any, _hookOrListener: any): void {
70+
[ɵProfilerEvent.TemplateUpdateStart](context: any, _hookOrListener: any): void {
7071
if (!this._inChangeDetection) {
7172
this._inChangeDetection = true;
7273
runOutsideAngular(() => {
@@ -77,19 +78,44 @@ export class NgProfiler extends Profiler {
7778
});
7879
}
7980

80-
const position = this._tracker.getDirectivePosition(directive);
81-
const id = this._tracker.getDirectiveId(directive);
81+
const position = this._tracker.getDirectivePosition(context);
82+
const id = this._tracker.getDirectiveId(context);
83+
84+
// If we can find the position and the ID we assume that this is a component instance.
85+
// Alternatively, if we can't find the ID or the position, we assume that this is a
86+
// context of an embedded view (for example, NgForOfContext, NgIfContext, or a custom one).
87+
if (position !== undefined && id !== undefined) {
88+
this._lastDirectiveInstance = context;
89+
}
90+
91+
if (id !== undefined && position !== undefined) {
92+
this._onChangeDetectionStart(context, getDirectiveHostElement(context), id, position);
93+
return;
94+
}
8295

83-
this._onChangeDetectionStart(directive, getDirectiveHostElement(directive), id, position);
96+
this._onChangeDetectionStart(
97+
this._lastDirectiveInstance,
98+
getDirectiveHostElement(this._lastDirectiveInstance),
99+
this._tracker.getDirectiveId(this._lastDirectiveInstance),
100+
this._tracker.getDirectivePosition(this._lastDirectiveInstance)
101+
);
84102
}
85103

86-
[ɵProfilerEvent.TemplateUpdateEnd](directive: any, _hookOrListener: any): void {
87-
const position = this._tracker.getDirectivePosition(directive);
88-
const id = this._tracker.getDirectiveId(directive);
104+
[ɵProfilerEvent.TemplateUpdateEnd](context: any, _hookOrListener: any): void {
105+
const position = this._tracker.getDirectivePosition(context);
106+
const id = this._tracker.getDirectiveId(context);
89107

90-
if (this._tracker.hasDirective(directive) && id !== undefined && position !== undefined) {
91-
this._onChangeDetectionEnd(directive, getDirectiveHostElement(directive), id, position);
108+
if (this._tracker.hasDirective(context) && id !== undefined && position !== undefined) {
109+
this._onChangeDetectionEnd(context, getDirectiveHostElement(context), id, position);
110+
return;
92111
}
112+
113+
this._onChangeDetectionEnd(
114+
this._lastDirectiveInstance,
115+
getDirectiveHostElement(this._lastDirectiveInstance),
116+
this._tracker.getDirectiveId(this._lastDirectiveInstance),
117+
this._tracker.getDirectivePosition(this._lastDirectiveInstance)
118+
);
93119
}
94120

95121
[ɵProfilerEvent.LifecycleHookStart](directive: any, hook: any): void {

0 commit comments

Comments
 (0)