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
This commit is contained in:
mgechev 2021-05-06 13:46:57 -07:00 committed by Alex Rickabaugh
parent 3927e2529a
commit 544e6a5ca1
2 changed files with 45 additions and 5 deletions

View File

@ -26,6 +26,7 @@ import {RComment, RElement, RNode, RText} from './interfaces/renderer_dom';
import {isLContainer, isLView} from './interfaces/type_checks';
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';
import {assertTNodeType} from './node_assert';
import {profiler, ProfilerEvent} from './profiler';
import {getLViewParent} from './util/view_traversal_utils';
import {getNativeByTNode, unwrapRNode, updateTransplantedViewCount} from './util/view_utils';
@ -506,10 +507,22 @@ function executeOnDestroys(tView: TView, lView: LView): void {
if (Array.isArray(toCall)) {
for (let j = 0; j < toCall.length; j += 2) {
(toCall[j + 1] as HookFn).call(context[toCall[j] as number]);
const callContext = context[toCall[j] as number];
const hook = toCall[j + 1] as HookFn;
profiler(ProfilerEvent.LifecycleHookStart, callContext, hook);
try {
hook.call(callContext);
} finally {
profiler(ProfilerEvent.LifecycleHookEnd, callContext, hook);
}
}
} else {
toCall.call(context);
profiler(ProfilerEvent.LifecycleHookStart, context, toCall);
try {
toCall.call(context);
} finally {
profiler(ProfilerEvent.LifecycleHookEnd, context, toCall);
}
}
}
}

View File

@ -11,7 +11,7 @@ import {TestBed} from '@angular/core/testing';
import {expect} from '@angular/core/testing/src/testing_internal';
import {onlyInIvy} from '@angular/private/testing';
import {AfterContentChecked, AfterContentInit, AfterViewChecked, AfterViewInit, Component, DoCheck, ErrorHandler, EventEmitter, Input, OnChanges, OnInit, Output, ViewChild} from '../../src/core';
import {AfterContentChecked, AfterContentInit, AfterViewChecked, AfterViewInit, Component, DoCheck, ErrorHandler, EventEmitter, Input, OnChanges, OnDestroy, OnInit, Output, ViewChild} from '../../src/core';
onlyInIvy('Ivy-specific functionality').describe('profiler', () => {
@ -187,13 +187,19 @@ onlyInIvy('Ivy-specific functionality').describe('profiler', () => {
describe('lifecycle hooks', () => {
it('should call the profiler on lifecycle execution', () => {
@Component({selector: 'my-comp', template: '{{prop}}'})
class Service implements OnDestroy {
ngOnDestroy() {}
}
@Component({selector: 'my-comp', template: '{{prop}}', providers: [Service]})
class MyComponent implements OnInit, AfterViewInit, AfterViewChecked, AfterContentInit,
AfterContentChecked, OnChanges, DoCheck {
AfterContentChecked, OnChanges, DoCheck, OnDestroy {
@Input() prop = 1;
constructor(private service: Service) {}
ngOnInit() {}
ngDoCheck() {}
ngOnDestroy() {}
ngOnChanges() {}
ngAfterViewInit() {}
ngAfterViewChecked() {}
@ -293,6 +299,27 @@ onlyInIvy('Ivy-specific functionality').describe('profiler', () => {
expect(onChangesSpy).toHaveBeenCalled();
expect(ngOnChangesStart).toBeTruthy();
expect(ngOnChangesEnd).toBeTruthy();
fixture.destroy();
const ngOnDestroyStart = findProfilerCall(
(args: any[]) =>
args[0] === ProfilerEvent.LifecycleHookStart && args[2] === myComp.ngOnDestroy);
const ngOnDestroyEnd = findProfilerCall(
(args: any[]) =>
args[0] === ProfilerEvent.LifecycleHookEnd && args[2] === myComp.ngOnDestroy);
expect(ngOnDestroyStart).toBeTruthy();
expect(ngOnDestroyEnd).toBeTruthy();
const serviceNgOnDestroyStart = findProfilerCall(
(args: any[]) => args[0] === ProfilerEvent.LifecycleHookStart &&
args[2] === Service.prototype.ngOnDestroy);
const serviceNgOnDestroyEnd = findProfilerCall(
(args: any[]) => args[0] === ProfilerEvent.LifecycleHookEnd &&
args[2] === Service.prototype.ngOnDestroy);
expect(serviceNgOnDestroyStart).toBeTruthy();
expect(serviceNgOnDestroyEnd).toBeTruthy();
});
});