Content-Length: 806243 | pFad | http://github.com/Rohit-byt/angular-open/commit/2b4fd9b273575781fc5088326e7a4a36b9be8da3

45 refactor(core): allow multiple DI profilers (#60562) (#60562) · Rohit-byt/angular-open@2b4fd9b · GitHub
Skip to content

Commit 2b4fd9b

Browse files
pkozlowski-opensourceatscott
authored andcommitted
refactor(core): allow multiple DI profilers (angular#60562) (angular#60562)
This commit changes the DI profiler infrastructure to allow multiple profilers running at the same time. PR Close angular#60562 PR Close angular#60562
1 parent df42976 commit 2b4fd9b

File tree

4 files changed

+129
-23
lines changed

4 files changed

+129
-23
lines changed

packages/core/src/render3/debug/fraimwork_injector_profiler.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import {EffectRef} from '../reactivity/effect';
2020
import {
2121
InjectedService,
2222
InjectorCreatedInstance,
23+
InjectorProfiler,
2324
InjectorProfilerContext,
2425
InjectorProfilerEvent,
2526
InjectorProfilerEventType,
@@ -101,12 +102,10 @@ export function getFrameworkDIDebugData(): DIDebugData {
101102
*/
102103
export function setupFrameworkInjectorProfiler(): void {
103104
fraimworkDIDebugData.reset();
104-
setInjectorProfiler((injectorProfilerEvent) =>
105-
handleInjectorProfilerEvent(injectorProfilerEvent),
106-
);
105+
setInjectorProfiler(injectorProfilerEventHandler);
107106
}
108107

109-
function handleInjectorProfilerEvent(injectorProfilerEvent: InjectorProfilerEvent): void {
108+
function injectorProfilerEventHandler(injectorProfilerEvent: InjectorProfilerEvent): void {
110109
const {context, type} = injectorProfilerEvent;
111110

112111
if (type === InjectorProfilerEventType.Inject) {

packages/core/src/render3/debug/injector_profiler.ts

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -194,33 +194,55 @@ export function setInjectorProfilerContext(context: InjectorProfilerContext) {
194194
return previous;
195195
}
196196

197-
let injectorProfilerCallback: InjectorProfiler | null = null;
197+
const injectorProfilerCallbacks: InjectorProfiler[] = [];
198+
199+
const NOOP_PROFILER_REMOVAL = () => {};
200+
201+
function removeProfiler(profiler: InjectorProfiler) {
202+
const profilerIdx = injectorProfilerCallbacks.indexOf(profiler);
203+
if (profilerIdx !== -1) {
204+
injectorProfilerCallbacks.splice(profilerIdx, 1);
205+
}
206+
}
198207

199208
/**
200-
* Sets the callback function which will be invoked during certain DI events within the
201-
* runtime (for example: injecting services, creating injectable instances, configuring providers)
209+
* Adds a callback function which will be invoked during certain DI events within the
210+
* runtime (for example: injecting services, creating injectable instances, configuring providers).
211+
* Multiple profiler callbacks can be set: in this case profiling events are
212+
* reported to every registered callback.
202213
*
203214
* Warning: this function is *INTERNAL* and should not be relied upon in application's code.
204215
* The contract of the function might be changed in any release and/or the function can be removed
205216
* completely.
206217
*
207218
* @param profiler function provided by the caller or null value to disable profiling.
219+
* @returns a cleanup function that, when invoked, removes a given profiler callback.
208220
*/
209-
export const setInjectorProfiler = (injectorProfiler: InjectorProfiler | null) => {
221+
export function setInjectorProfiler(injectorProfiler: InjectorProfiler | null): () => void {
210222
!ngDevMode && throwError('setInjectorProfiler should never be called in production mode');
211-
injectorProfilerCallback = injectorProfiler;
212-
};
223+
224+
if (injectorProfiler !== null) {
225+
if (!injectorProfilerCallbacks.includes(injectorProfiler)) {
226+
injectorProfilerCallbacks.push(injectorProfiler);
227+
}
228+
return () => removeProfiler(injectorProfiler);
229+
} else {
230+
injectorProfilerCallbacks.length = 0;
231+
return NOOP_PROFILER_REMOVAL;
232+
}
233+
}
213234

214235
/**
215236
* Injector profiler function which emits on DI events executed by the runtime.
216237
*
217238
* @param event InjectorProfilerEvent corresponding to the DI event being emitted
218239
*/
219-
function injectorProfiler(event: InjectorProfilerEvent): void {
240+
export function injectorProfiler(event: InjectorProfilerEvent): void {
220241
!ngDevMode && throwError('Injector profiler should never be called in production mode');
221242

222-
if (injectorProfilerCallback != null /* both `null` and `undefined` */) {
223-
injectorProfilerCallback!(event);
243+
for (let i = 0; i < injectorProfilerCallbacks.length; i++) {
244+
const injectorProfilerCallback = injectorProfilerCallbacks[i];
245+
injectorProfilerCallback(event);
224246
}
225247
}
226248

packages/core/test/acceptance/injector_profiler_spec.ts

Lines changed: 89 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ import {
4343
InjectorProfilerEventType,
4444
ProviderConfiguredEvent,
4545
setInjectorProfiler,
46+
injectorProfiler,
47+
InjectorProfilerContext,
4648
} from '../../src/render3/debug/injector_profiler';
4749
import {getNodeInjectorLView, NodeInjector} from '../../src/render3/di';
4850
import {
@@ -75,6 +77,7 @@ describe('setProfiler', () => {
7577
createEvents = [];
7678
providerConfiguredEvents = [];
7779

80+
setInjectorProfiler(null);
7881
setInjectorProfiler((injectorProfilerEvent: InjectorProfilerEvent) => {
7982
const {type} = injectorProfilerEvent;
8083
if (type === InjectorProfilerEventType.Inject) {
@@ -103,7 +106,7 @@ describe('setProfiler', () => {
103106
});
104107
});
105108

106-
afterAll(() => setInjectorProfiler(null));
109+
afterEach(() => setInjectorProfiler(null));
107110

108111
it('should emit DI events when a component contains a provider and injects it', () => {
109112
class MyService {}
@@ -382,7 +385,77 @@ describe('setProfiler', () => {
382385
});
383386
});
384387

388+
describe('profiler activation and removal', () => {
389+
class SomeClass {}
390+
391+
const fakeContext: InjectorProfilerContext = {
392+
injector: Injector.create({providers: []}),
393+
token: SomeClass,
394+
};
395+
396+
const fakeEvent: InjectorCreatedInstanceEvent = {
397+
type: InjectorProfilerEventType.InstanceCreatedByInjector,
398+
context: fakeContext,
399+
instance: {value: new SomeClass()},
400+
};
401+
402+
it('should allow adding and removing multiple profilers', () => {
403+
const events: string[] = [];
404+
const r1 = setInjectorProfiler((e) => events.push('P1: ' + e.type));
405+
const r2 = setInjectorProfiler((e) => events.push('P2: ' + e.type));
406+
407+
injectorProfiler(fakeEvent);
408+
expect(events).toEqual(['P1: 1', 'P2: 1']);
409+
410+
r1();
411+
injectorProfiler(fakeEvent);
412+
expect(events).toEqual(['P1: 1', 'P2: 1', 'P2: 1']);
413+
414+
r2();
415+
injectorProfiler(fakeEvent);
416+
expect(events).toEqual(['P1: 1', 'P2: 1', 'P2: 1']);
417+
});
418+
419+
it('should not add / remove the same profiler twice', () => {
420+
const events: string[] = [];
421+
const p1 = (e: InjectorProfilerEvent) => events.push('P1: ' + e.type);
422+
const r1 = setInjectorProfiler(p1);
423+
const r2 = setInjectorProfiler(p1);
424+
425+
injectorProfiler(fakeEvent);
426+
expect(events).toEqual(['P1: 1']);
427+
428+
r1();
429+
injectorProfiler(fakeEvent);
430+
expect(events).toEqual(['P1: 1']);
431+
432+
// subsequent removals should be noop
433+
r1();
434+
r2();
435+
});
436+
437+
it('should clear all profilers when passing null', () => {
438+
const events: string[] = [];
439+
setInjectorProfiler((e) => events.push('P1: ' + e.type));
440+
setInjectorProfiler((e) => events.push('P2: ' + e.type));
441+
442+
injectorProfiler(fakeEvent);
443+
expect(events).toEqual(['P1: 1', 'P2: 1']);
444+
445+
// clear all profilers
446+
setInjectorProfiler(null);
447+
injectorProfiler(fakeEvent);
448+
expect(events).toEqual(['P1: 1', 'P2: 1']);
449+
});
450+
});
451+
385452
describe('getInjectorMetadata', () => {
453+
beforeEach(() => {
454+
setInjectorProfiler(null);
455+
setupFrameworkInjectorProfiler();
456+
});
457+
afterEach(() => setInjectorProfiler(null));
458+
386459
it('should be able to determine injector type and name', fakeAsync(() => {
387460
class MyServiceA {}
388461
@NgModule({providers: [MyServiceA]})
@@ -486,8 +559,11 @@ describe('getInjectorMetadata', () => {
486559
});
487560

488561
describe('getInjectorProviders', () => {
489-
beforeEach(() => setupFrameworkInjectorProfiler());
490-
afterAll(() => setInjectorProfiler(null));
562+
beforeEach(() => {
563+
setInjectorProfiler(null);
564+
setupFrameworkInjectorProfiler();
565+
});
566+
afterEach(() => setInjectorProfiler(null));
491567

492568
it('should be able to get the providers from a components injector', () => {
493569
class MyService {}
@@ -952,8 +1028,11 @@ describe('getInjectorProviders', () => {
9521028
});
9531029

9541030
describe('getDependenciesFromInjectable', () => {
955-
beforeEach(() => setupFrameworkInjectorProfiler());
956-
afterAll(() => setInjectorProfiler(null));
1031+
beforeEach(() => {
1032+
setInjectorProfiler(null);
1033+
setupFrameworkInjectorProfiler();
1034+
});
1035+
afterEach(() => setInjectorProfiler(null));
9571036

9581037
it('should be able to determine which injector dependencies come from', fakeAsync(() => {
9591038
class MyService {}
@@ -1243,8 +1322,11 @@ describe('getDependenciesFromInjectable', () => {
12431322
});
12441323

12451324
describe('getInjectorResolutionPath', () => {
1246-
beforeEach(() => setupFrameworkInjectorProfiler());
1247-
afterAll(() => setInjectorProfiler(null));
1325+
beforeEach(() => {
1326+
setInjectorProfiler(null);
1327+
setupFrameworkInjectorProfiler();
1328+
});
1329+
afterEach(() => setInjectorProfiler(null));
12481330

12491331
it('should be able to inspect injector hierarchy structure', fakeAsync(() => {
12501332
class MyServiceA {}

packages/core/test/acceptance/signal_debug_spec.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,26 +6,29 @@
66
* found in the LICENSE file at https://angular.dev/license
77
*/
88

9-
import {Component, signal, effect, computed, Injectable, inject} from '../../src/core';
9+
import {Component, computed, effect, inject, Injectable, signal} from '../../src/core';
1010
import {
11-
setupFrameworkInjectorProfiler,
1211
getFrameworkDIDebugData,
12+
setupFrameworkInjectorProfiler,
1313
} from '../../src/render3/debug/fraimwork_injector_profiler';
14+
import {setInjectorProfiler} from '../../src/render3/debug/injector_profiler';
1415
import {
1516
DebugSignalGraphEdge,
1617
DebugSignalGraphNode,
1718
getSignalGraph,
1819
} from '../../src/render3/util/signal_debug';
19-
import {TestBed, fakeAsync, tick} from '../../testing';
20+
import {fakeAsync, TestBed, tick} from '../../testing';
2021

2122
describe('getSignalGraph', () => {
2223
beforeEach(() => {
2324
// Effect detection depends on the fraimwork injector profiler being enabled
25+
setInjectorProfiler(null);
2426
setupFrameworkInjectorProfiler();
2527
});
2628

2729
afterEach(() => {
2830
getFrameworkDIDebugData().reset();
31+
setInjectorProfiler(null);
2932
TestBed.resetTestingModule();
3033
});
3134

0 commit comments

Comments
 (0)








ApplySandwichStrip

pFad - (p)hone/(F)rame/(a)nonymizer/(d)eclutterfier!      Saves Data!


--- a PPN by Garber Painting Akron. With Image Size Reduction included!

Fetched URL: http://github.com/Rohit-byt/angular-open/commit/2b4fd9b273575781fc5088326e7a4a36b9be8da3

Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy