Skip to content

Commit 40cc29a

Browse files
mgechevalxhub
authored andcommittedMay 7, 2021
fix(core): invoke profiler around ngOnDestroy lifecycle hooks (#41969)
Invoke the profiler for `ngOnDestroy` lifecycle hooks for services, components, directives, and pipes. PR Close #41969
1 parent 9883dab commit 40cc29a

File tree

2 files changed

+45
-5
lines changed

2 files changed

+45
-5
lines changed
 

Diff for: ‎packages/core/src/render3/node_manipulation.ts

+15-2
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import {RComment, RElement, RNode, RText} from './interfaces/renderer_dom';
2626
import {isLContainer, isLView} from './interfaces/type_checks';
2727
import {CHILD_HEAD, CLEANUP, DECLARATION_COMPONENT_VIEW, DECLARATION_LCONTAINER, DestroyHookData, FLAGS, HookData, HookFn, HOST, LView, LViewFlags, NEXT, PARENT, QUERIES, RENDERER, T_HOST, TVIEW, TView, TViewType, unusedValueExportToPlacateAjd as unused5} from './interfaces/view';
2828
import {assertTNodeType} from './node_assert';
29+
import {profiler, ProfilerEvent} from './profiler';
2930
import {getLViewParent} from './util/view_traversal_utils';
3031
import {getNativeByTNode, unwrapRNode, updateTransplantedViewCount} from './util/view_utils';
3132

@@ -506,10 +507,22 @@ function executeOnDestroys(tView: TView, lView: LView): void {
506507

507508
if (Array.isArray(toCall)) {
508509
for (let j = 0; j < toCall.length; j += 2) {
509-
(toCall[j + 1] as HookFn).call(context[toCall[j] as number]);
510+
const callContext = context[toCall[j] as number];
511+
const hook = toCall[j + 1] as HookFn;
512+
profiler(ProfilerEvent.LifecycleHookStart, callContext, hook);
513+
try {
514+
hook.call(callContext);
515+
} finally {
516+
profiler(ProfilerEvent.LifecycleHookEnd, callContext, hook);
517+
}
510518
}
511519
} else {
512-
toCall.call(context);
520+
profiler(ProfilerEvent.LifecycleHookStart, context, toCall);
521+
try {
522+
toCall.call(context);
523+
} finally {
524+
profiler(ProfilerEvent.LifecycleHookEnd, context, toCall);
525+
}
513526
}
514527
}
515528
}

Diff for: ‎packages/core/test/acceptance/profiler_spec.ts

+30-3
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import {TestBed} from '@angular/core/testing';
1111
import {expect} from '@angular/core/testing/src/testing_internal';
1212
import {onlyInIvy} from '@angular/private/testing';
1313

14-
import {AfterContentChecked, AfterContentInit, AfterViewChecked, AfterViewInit, Component, DoCheck, ErrorHandler, EventEmitter, Input, OnChanges, OnInit, Output, ViewChild} from '../../src/core';
14+
import {AfterContentChecked, AfterContentInit, AfterViewChecked, AfterViewInit, Component, DoCheck, ErrorHandler, EventEmitter, Input, OnChanges, OnDestroy, OnInit, Output, ViewChild} from '../../src/core';
1515

1616

1717
onlyInIvy('Ivy-specific functionality').describe('profiler', () => {
@@ -187,13 +187,19 @@ onlyInIvy('Ivy-specific functionality').describe('profiler', () => {
187187

188188
describe('lifecycle hooks', () => {
189189
it('should call the profiler on lifecycle execution', () => {
190-
@Component({selector: 'my-comp', template: '{{prop}}'})
190+
class Service implements OnDestroy {
191+
ngOnDestroy() {}
192+
}
193+
@Component({selector: 'my-comp', template: '{{prop}}', providers: [Service]})
191194
class MyComponent implements OnInit, AfterViewInit, AfterViewChecked, AfterContentInit,
192-
AfterContentChecked, OnChanges, DoCheck {
195+
AfterContentChecked, OnChanges, DoCheck, OnDestroy {
193196
@Input() prop = 1;
194197

198+
constructor(private service: Service) {}
199+
195200
ngOnInit() {}
196201
ngDoCheck() {}
202+
ngOnDestroy() {}
197203
ngOnChanges() {}
198204
ngAfterViewInit() {}
199205
ngAfterViewChecked() {}
@@ -293,6 +299,27 @@ onlyInIvy('Ivy-specific functionality').describe('profiler', () => {
293299
expect(onChangesSpy).toHaveBeenCalled();
294300
expect(ngOnChangesStart).toBeTruthy();
295301
expect(ngOnChangesEnd).toBeTruthy();
302+
303+
fixture.destroy();
304+
const ngOnDestroyStart = findProfilerCall(
305+
(args: any[]) =>
306+
args[0] === ProfilerEvent.LifecycleHookStart && args[2] === myComp.ngOnDestroy);
307+
const ngOnDestroyEnd = findProfilerCall(
308+
(args: any[]) =>
309+
args[0] === ProfilerEvent.LifecycleHookEnd && args[2] === myComp.ngOnDestroy);
310+
311+
expect(ngOnDestroyStart).toBeTruthy();
312+
expect(ngOnDestroyEnd).toBeTruthy();
313+
314+
const serviceNgOnDestroyStart = findProfilerCall(
315+
(args: any[]) => args[0] === ProfilerEvent.LifecycleHookStart &&
316+
args[2] === Service.prototype.ngOnDestroy);
317+
const serviceNgOnDestroyEnd = findProfilerCall(
318+
(args: any[]) => args[0] === ProfilerEvent.LifecycleHookEnd &&
319+
args[2] === Service.prototype.ngOnDestroy);
320+
321+
expect(serviceNgOnDestroyStart).toBeTruthy();
322+
expect(serviceNgOnDestroyEnd).toBeTruthy();
296323
});
297324
});
298325

0 commit comments

Comments
 (0)