Skip to content

Commit c970705

Browse files
committed
perf(popover-edit): collect common services into a single class for dependency injection
I measured a savings of 0.023ms per CdkPopoverEdit instance at startup. There should also be additional savings in CdkRowHoverContent that I did not measure.
1 parent 3e17ce7 commit c970705

File tree

3 files changed

+59
-56
lines changed

3 files changed

+59
-56
lines changed
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
import {Injectable, NgZone} from '@angular/core';
10+
import {FocusTrapFactory} from '@angular/cdk/a11y';
11+
import {Overlay} from '@angular/cdk/overlay';
12+
import {ScrollDispatcher, ViewportRuler} from '@angular/cdk/scrolling';
13+
14+
import {EditEventDispatcher} from './edit-event-dispatcher';
15+
import {FocusDispatcher} from './focus-dispatcher';
16+
import {PopoverEditPositionStrategyFactory} from './popover-edit-position-strategy-factory';
17+
18+
/**
19+
* Optimization
20+
* Collects multiple Injectables into a singleton shared across the table. By reducing the
21+
* number of services injected into each CdkPopoverEdit, this saves about 0.023ms of cpu time
22+
* and 56 bytes of memory per instance.
23+
*/
24+
@Injectable()
25+
export class EditServices {
26+
constructor(
27+
readonly editEventDispatcher: EditEventDispatcher, readonly focusDispatcher: FocusDispatcher,
28+
readonly focusTrapFactory: FocusTrapFactory, readonly ngZone: NgZone,
29+
readonly overlay: Overlay, readonly positionFactory: PopoverEditPositionStrategyFactory,
30+
readonly scrollDispatcher: ScrollDispatcher, readonly viewportRuler: ViewportRuler) {}
31+
}

src/cdk-experimental/popover-edit/popover-edit.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -316,7 +316,7 @@ const testCases: ReadonlyArray<[Type<BaseTestComponent>, string]> = [
316316
];
317317

318318
describe('CDK Popover Edit', () => {
319-
for (const [componentClass, label] of testCases.slice(0, 1)) {
319+
for (const [componentClass, label] of testCases) {
320320
describe(label, () => {
321321
let component: BaseTestComponent;
322322
let fixture: ComponentFixture<BaseTestComponent>;

src/cdk-experimental/popover-edit/table-directives.ts

Lines changed: 27 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,9 @@
55
* Use of this source code is governed by an MIT-style license that can be
66
* found in the LICENSE file at https://angular.io/license
77
*/
8-
import {FocusTrap, FocusTrapFactory} from '@angular/cdk/a11y';
9-
import {Overlay, OverlayRef, PositionStrategy} from '@angular/cdk/overlay';
8+
import {FocusTrap} from '@angular/cdk/a11y';
9+
import {OverlayRef, PositionStrategy} from '@angular/cdk/overlay';
1010
import {TemplatePortal} from '@angular/cdk/portal';
11-
import {ScrollDispatcher, ViewportRuler} from '@angular/cdk/scrolling';
1211
import {
1312
AfterViewInit,
1413
Directive,
@@ -25,14 +24,14 @@ import {debounceTime, filter, map, mapTo, startWith, takeUntil} from 'rxjs/opera
2524

2625
import {CELL_SELECTOR, EDIT_PANE_CLASS, EDIT_PANE_SELECTOR, ROW_SELECTOR} from './constants';
2726
import {EditEventDispatcher} from './edit-event-dispatcher';
27+
import {EditServices} from './edit-services';
2828
import {FocusDispatcher} from './focus-dispatcher';
2929
import {
3030
FocusEscapeNotifier,
3131
FocusEscapeNotifierDirection,
3232
FocusEscapeNotifierFactory
3333
} from './focus-escape-notifier';
3434
import {closest} from './polyfill';
35-
import {PopoverEditPositionStrategyFactory} from './popover-edit-position-strategy-factory';
3635

3736
/**
3837
* Describes the number of columns before and after the originating cell that the
@@ -57,7 +56,7 @@ const DEFAULT_MOUSE_MOVE_DELAY_MS = 30;
5756
*/
5857
@Directive({
5958
selector: 'table[editable], cdk-table[editable], mat-table[editable]',
60-
providers: [EditEventDispatcher],
59+
providers: [EditEventDispatcher, EditServices],
6160
})
6261
export class CdkEditable implements AfterViewInit, OnDestroy {
6362
protected readonly destroyed = new ReplaySubject<void>();
@@ -161,15 +160,8 @@ export class CdkPopoverEdit<C> implements AfterViewInit, OnDestroy {
161160
protected readonly destroyed = new ReplaySubject<void>();
162161

163162
constructor(
164-
protected readonly editEventDispatcher: EditEventDispatcher,
165-
protected readonly elementRef: ElementRef,
166-
protected readonly focusTrapFactory: FocusTrapFactory,
167-
protected readonly ngZone: NgZone,
168-
protected readonly overlay: Overlay,
169-
protected readonly positionFactory: PopoverEditPositionStrategyFactory,
170-
protected readonly scrollDispatcher: ScrollDispatcher,
171-
protected readonly viewContainerRef: ViewContainerRef,
172-
protected readonly viewportRuler: ViewportRuler) {}
163+
protected readonly services: EditServices, protected readonly elementRef: ElementRef,
164+
protected readonly viewContainerRef: ViewContainerRef) {}
173165

174166
ngAfterViewInit(): void {
175167
this._startListeningToEditEvents();
@@ -185,18 +177,18 @@ export class CdkPopoverEdit<C> implements AfterViewInit, OnDestroy {
185177
}
186178

187179
protected initFocusTrap(): void {
188-
this.focusTrap = this.focusTrapFactory.create(this.overlayRef!.overlayElement);
180+
this.focusTrap = this.services.focusTrapFactory.create(this.overlayRef!.overlayElement);
189181
}
190182

191183
protected closeEditOverlay(): void {
192-
this.editEventDispatcher.doneEditingCell(this.elementRef.nativeElement!);
184+
this.services.editEventDispatcher.doneEditingCell(this.elementRef.nativeElement!);
193185
}
194186

195187
private _startListeningToEditEvents(): void {
196-
this.editEventDispatcher.editingCell(this.elementRef.nativeElement!)
188+
this.services.editEventDispatcher.editingCell(this.elementRef.nativeElement!)
197189
.pipe(takeUntil(this.destroyed))
198190
.subscribe((open) => {
199-
this.ngZone.run(() => {
191+
this.services.ngZone.run(() => {
200192
if (open && this.template) {
201193
if (!this.overlayRef) {
202194
this._createEditOverlay();
@@ -209,15 +201,15 @@ export class CdkPopoverEdit<C> implements AfterViewInit, OnDestroy {
209201
this.overlayRef.detach();
210202
}
211203
});
212-
});
204+
});
213205
}
214206

215207
private _createEditOverlay(): void {
216-
this.overlayRef = this.overlay.create({
208+
this.overlayRef = this.services.overlay.create({
217209
disposeOnNavigation: true,
218210
panelClass: EDIT_PANE_CLASS,
219211
positionStrategy: this._getPositionStrategy(),
220-
scrollStrategy: this.overlay.scrollStrategies.reposition(),
212+
scrollStrategy: this.services.overlay.scrollStrategies.reposition(),
221213
});
222214

223215
this.initFocusTrap();
@@ -235,7 +227,7 @@ export class CdkPopoverEdit<C> implements AfterViewInit, OnDestroy {
235227

236228
// Update the size of the popup initially and on subsequent changes to
237229
// scroll position and viewport size.
238-
merge(this.scrollDispatcher.scrolled(), this.viewportRuler.change())
230+
merge(this.services.scrollDispatcher.scrolled(), this.services.viewportRuler.change())
239231
.pipe(
240232
startWith(null),
241233
takeUntil(this.overlayRef!.detachments()),
@@ -262,11 +254,12 @@ export class CdkPopoverEdit<C> implements AfterViewInit, OnDestroy {
262254
}
263255

264256
private _getPositionStrategy(): PositionStrategy {
265-
return this.positionFactory.positionStrategyForCells(this._getOverlayCells());
257+
return this.services.positionFactory.positionStrategyForCells(this._getOverlayCells());
266258
}
267259

268260
private _updateOverlaySize(): void {
269-
this.overlayRef!.updateSize(this.positionFactory.sizeConfigForCells(this._getOverlayCells()));
261+
this.overlayRef!.updateSize(
262+
this.services.positionFactory.sizeConfigForCells(this._getOverlayCells()));
270263
}
271264

272265
private _maybeReturnFocusToCell(): void {
@@ -294,38 +287,20 @@ export class CdkPopoverEditTabOut<C> extends CdkPopoverEdit<C> {
294287
protected focusTrap?: FocusEscapeNotifier;
295288

296289
constructor(
297-
editEventDispatcher: EditEventDispatcher,
298-
elementRef: ElementRef,
299-
focusTrapFactory: FocusTrapFactory,
300-
ngZone: NgZone,
301-
overlay: Overlay,
302-
positionFactory: PopoverEditPositionStrategyFactory,
303-
scrollDispatcher: ScrollDispatcher,
304-
viewContainerRef: ViewContainerRef,
305-
viewportRuler: ViewportRuler,
306-
protected readonly focusEscapeNotifierFactory: FocusEscapeNotifierFactory,
307-
protected readonly focusDispatcher: FocusDispatcher) {
308-
super(
309-
editEventDispatcher,
310-
elementRef,
311-
focusTrapFactory,
312-
ngZone,
313-
overlay,
314-
positionFactory,
315-
scrollDispatcher,
316-
viewContainerRef,
317-
viewportRuler);
290+
elementRef: ElementRef, viewContainerRef: ViewContainerRef, services: EditServices,
291+
protected readonly focusEscapeNotifierFactory: FocusEscapeNotifierFactory) {
292+
super(services, elementRef, viewContainerRef);
318293
}
319294

320295
protected initFocusTrap(): void {
321296
this.focusTrap = this.focusEscapeNotifierFactory.create(this.overlayRef!.overlayElement);
322297

323298
this.focusTrap.escapes().pipe(takeUntil(this.destroyed)).subscribe(direction => {
324-
if (this.editEventDispatcher.editRef) {
325-
this.editEventDispatcher.editRef.blur();
299+
if (this.services.editEventDispatcher.editRef) {
300+
this.services.editEventDispatcher.editRef.blur();
326301
}
327302

328-
this.focusDispatcher.moveFocusHorizontally(
303+
this.services.focusDispatcher.moveFocusHorizontally(
329304
closest(this.elementRef.nativeElement!, CELL_SELECTOR) as HTMLElement,
330305
direction === FocusEscapeNotifierDirection.START ? -1 : 1);
331306

@@ -358,12 +333,9 @@ export class CdkRowHoverContent implements AfterViewInit, OnDestroy {
358333
protected viewRef: EmbeddedViewRef<any>|null = null;
359334

360335
constructor(
361-
protected readonly elementRef: ElementRef,
362-
protected readonly editEventDispatcher: EditEventDispatcher,
363-
protected readonly ngZone: NgZone,
336+
protected readonly services: EditServices, protected readonly elementRef: ElementRef,
364337
protected readonly templateRef: TemplateRef<any>,
365-
protected readonly viewContainerRef: ViewContainerRef
366-
) {}
338+
protected readonly viewContainerRef: ViewContainerRef) {}
367339

368340
ngAfterViewInit(): void {
369341
this._listenForHoverEvents();
@@ -379,10 +351,10 @@ export class CdkRowHoverContent implements AfterViewInit, OnDestroy {
379351
}
380352

381353
private _listenForHoverEvents(): void {
382-
this.editEventDispatcher.hoveringOnRow(this.elementRef.nativeElement!)
354+
this.services.editEventDispatcher.hoveringOnRow(this.elementRef.nativeElement!)
383355
.pipe(takeUntil(this.destroyed))
384356
.subscribe(isHovering => {
385-
this.ngZone.run(() => {
357+
this.services.ngZone.run(() => {
386358
if (isHovering) {
387359
if (!this.viewRef) {
388360
// Not doing any positioning in CDK version. Material version

0 commit comments

Comments
 (0)