diff --git a/packages/core/src/render3/debug/injector_profiler.ts b/packages/core/src/render3/debug/injector_profiler.ts index 955c437ed81..509c2763014 100644 --- a/packages/core/src/render3/debug/injector_profiler.ts +++ b/packages/core/src/render3/debug/injector_profiler.ts @@ -194,55 +194,33 @@ export function setInjectorProfilerContext(context: InjectorProfilerContext) { return previous; } -const injectorProfilerCallbacks: InjectorProfiler[] = []; - -const NOOP_PROFILER_REMOVAL = () => {}; - -function removeProfiler(profiler: InjectorProfiler) { - const profilerIdx = injectorProfilerCallbacks.indexOf(profiler); - if (profilerIdx !== -1) { - injectorProfilerCallbacks.splice(profilerIdx, 1); - } -} +let injectorProfilerCallback: InjectorProfiler | null = null; /** - * Adds a callback function which will be invoked during certain DI events within the - * runtime (for example: injecting services, creating injectable instances, configuring providers). - * Multiple profiler callbacks can be set: in this case profiling events are - * reported to every registered callback. + * Sets the callback function which will be invoked during certain DI events within the + * runtime (for example: injecting services, creating injectable instances, configuring providers) * * Warning: this function is *INTERNAL* and should not be relied upon in application's code. * The contract of the function might be changed in any release and/or the function can be removed * completely. * * @param profiler function provided by the caller or null value to disable profiling. - * @returns a cleanup function that, when invoked, removes a given profiler callback. */ -export function setInjectorProfiler(injectorProfiler: InjectorProfiler | null): () => void { +export const setInjectorProfiler = (injectorProfiler: InjectorProfiler | null) => { !ngDevMode && throwError('setInjectorProfiler should never be called in production mode'); - - if (injectorProfiler !== null) { - if (!injectorProfilerCallbacks.includes(injectorProfiler)) { - injectorProfilerCallbacks.push(injectorProfiler); - } - return () => removeProfiler(injectorProfiler); - } else { - injectorProfilerCallbacks.length = 0; - return NOOP_PROFILER_REMOVAL; - } -} + injectorProfilerCallback = injectorProfiler; +}; /** * Injector profiler function which emits on DI events executed by the runtime. * * @param event InjectorProfilerEvent corresponding to the DI event being emitted */ -export function injectorProfiler(event: InjectorProfilerEvent): void { +function injectorProfiler(event: InjectorProfilerEvent): void { !ngDevMode && throwError('Injector profiler should never be called in production mode'); - for (let i = 0; i < injectorProfilerCallbacks.length; i++) { - const injectorProfilerCallback = injectorProfilerCallbacks[i]; - injectorProfilerCallback(event); + if (injectorProfilerCallback != null /* both `null` and `undefined` */) { + injectorProfilerCallback!(event); } } diff --git a/packages/core/test/acceptance/injector_profiler_spec.ts b/packages/core/test/acceptance/injector_profiler_spec.ts index f3770accf76..f8f4046582a 100644 --- a/packages/core/test/acceptance/injector_profiler_spec.ts +++ b/packages/core/test/acceptance/injector_profiler_spec.ts @@ -11,7 +11,6 @@ import { afterRender, ClassProvider, Component, - createEnvironmentInjector, Directive, ElementRef, inject, @@ -44,8 +43,6 @@ import { InjectorProfilerEventType, ProviderConfiguredEvent, setInjectorProfiler, - injectorProfiler, - InjectorProfilerContext, } from '../../src/render3/debug/injector_profiler'; import {getNodeInjectorLView, NodeInjector} from '../../src/render3/di'; import { @@ -106,7 +103,7 @@ describe('setProfiler', () => { }); }); - afterEach(() => setInjectorProfiler(null)); + afterAll(() => setInjectorProfiler(null)); it('should emit DI events when a component contains a provider and injects it', () => { class MyService {} @@ -385,70 +382,6 @@ describe('setProfiler', () => { }); }); -describe('profiler activation and removal', () => { - class SomeClass {} - - const fakeContext: InjectorProfilerContext = { - injector: Injector.create({providers: []}), - token: SomeClass, - }; - - const fakeEvent: InjectorCreatedInstanceEvent = { - type: InjectorProfilerEventType.InstanceCreatedByInjector, - context: fakeContext, - instance: {value: new SomeClass()}, - }; - - it('should allow adding and removing multiple profilers', () => { - const events: string[] = []; - const r1 = setInjectorProfiler((e) => events.push('P1: ' + e.type)); - const r2 = setInjectorProfiler((e) => events.push('P2: ' + e.type)); - - injectorProfiler(fakeEvent); - expect(events).toEqual(['P1: 1', 'P2: 1']); - - r1(); - injectorProfiler(fakeEvent); - expect(events).toEqual(['P1: 1', 'P2: 1', 'P2: 1']); - - r2(); - injectorProfiler(fakeEvent); - expect(events).toEqual(['P1: 1', 'P2: 1', 'P2: 1']); - }); - - it('should not add / remove the same profiler twice', () => { - const events: string[] = []; - const p1 = (e: InjectorProfilerEvent) => events.push('P1: ' + e.type); - const r1 = setInjectorProfiler(p1); - const r2 = setInjectorProfiler(p1); - - injectorProfiler(fakeEvent); - expect(events).toEqual(['P1: 1']); - - r1(); - injectorProfiler(fakeEvent); - expect(events).toEqual(['P1: 1']); - - // subsequent removals should be noop - r1(); - r2(); - }); - - it('should clear all profilers when passing null', () => { - const events: string[] = []; - setInjectorProfiler((e) => events.push('P1: ' + e.type)); - setInjectorProfiler((e) => events.push('P2: ' + e.type)); - - injectorProfiler(fakeEvent); - expect(events).toEqual(['P1: 1', 'P2: 1']); - - // clear all profilers - setInjectorProfiler(null); - injectorProfiler(fakeEvent); - expect(events).toEqual(['P1: 1', 'P2: 1']); - }); -}); - describe('getInjectorMetadata', () => { it('should be able to determine injector type and name', fakeAsync(() => { class MyServiceA {} @@ -554,7 +487,7 @@ describe('getInjectorMetadata', () => { describe('getInjectorProviders', () => { beforeEach(() => setupFrameworkInjectorProfiler()); - afterEach(() => setInjectorProfiler(null)); + afterAll(() => setInjectorProfiler(null)); it('should be able to get the providers from a components injector', () => { class MyService {} @@ -1020,7 +953,7 @@ describe('getInjectorProviders', () => { describe('getDependenciesFromInjectable', () => { beforeEach(() => setupFrameworkInjectorProfiler()); - afterEach(() => setInjectorProfiler(null)); + afterAll(() => setInjectorProfiler(null)); it('should be able to determine which injector dependencies come from', fakeAsync(() => { class MyService {} @@ -1311,7 +1244,7 @@ describe('getDependenciesFromInjectable', () => { describe('getInjectorResolutionPath', () => { beforeEach(() => setupFrameworkInjectorProfiler()); - afterEach(() => setInjectorProfiler(null)); + afterAll(() => setInjectorProfiler(null)); it('should be able to inspect injector hierarchy structure', fakeAsync(() => { class MyServiceA {}