perf(tabs): avoid extra resize handler and reflow (#6434)

In #6304, an extra window resize handler was added in order to call `_checkPaginationEnabled`. This handler is unnecessary, because we have another resize handler a little bit below that calls `_updatePagination`, which will call `_checkPaginationEnabled` internally. The original issue that #6304 was fixing was due to the fact that the current listener wasn't being run in the Angular zone. These changes remove the extra listener, increase the debounce interval and move the handler outside back into the zone. There may be a slight overhead from moving the listener into the zone, however it should be offset by not having another listener and not calling `_checkPaginationEnabled` twice.
This commit is contained in:
Kristiyan Kostadinov
2017-08-15 23:48:16 +02:00
committed by Andrew Seguin
parent 5d437ea861
commit 1df79e9efa
2 changed files with 20 additions and 39 deletions
+1 -1
View File
@@ -259,7 +259,7 @@ describe('MdTabHeader', () => {
spyOn(inkBar, 'alignToElement');
dispatchFakeEvent(window, 'resize');
tick(10);
tick(150);
fixture.detectChanges();
expect(inkBar.alignToElement).toHaveBeenCalled();
+19 -38
View File
@@ -20,10 +20,9 @@ import {
AfterContentChecked,
AfterContentInit,
OnDestroy,
NgZone,
Renderer2,
ChangeDetectionStrategy,
ChangeDetectorRef
ChangeDetectorRef,
} from '@angular/core';
import {Directionality, Direction} from '@angular/cdk/bidi';
import {RIGHT_ARROW, LEFT_ARROW, ENTER} from '@angular/cdk/keycodes';
@@ -35,8 +34,6 @@ import {fromEvent} from 'rxjs/observable/fromEvent';
import {MdTabLabelWrapper} from './tab-label-wrapper';
import {MdInkBar} from './ink-bar';
import {CanDisableRipple, mixinDisableRipple} from '../core/common-behaviors/disable-ripple';
import {RxChain, debounceTime} from '@angular/cdk/rxjs';
import {Platform} from '@angular/cdk/platform';
/**
* The directions that scrolling can go in when the header's tabs exceed the header width. 'After'
@@ -117,15 +114,11 @@ export class MdTabHeader extends _MdTabHeaderMixinBase
private _selectedIndex: number = 0;
/** subscription for the window resize handler */
private _resizeSubscription: Subscription | null;
/** The index of the active tab. */
@Input()
get selectedIndex(): number { return this._selectedIndex; }
set selectedIndex(value: number) {
this._selectedIndexChanged = this._selectedIndex != value;
this._selectedIndex = value;
this._focusIndex = value;
}
@@ -137,19 +130,10 @@ export class MdTabHeader extends _MdTabHeaderMixinBase
@Output() indexFocused = new EventEmitter();
constructor(private _elementRef: ElementRef,
private _ngZone: NgZone,
private _renderer: Renderer2,
private _changeDetectorRef: ChangeDetectorRef,
@Optional() private _dir: Directionality,
platform: Platform) {
@Optional() private _dir: Directionality) {
super();
if (platform.isBrowser) {
// TODO: Add library level window listener https://goo.gl/y25X5M
this._resizeSubscription = RxChain.from(fromEvent(window, 'resize'))
.call(debounceTime, 150)
.subscribe(() => this._checkPaginationEnabled());
}
}
ngAfterContentChecked(): void {
@@ -197,16 +181,14 @@ export class MdTabHeader extends _MdTabHeaderMixinBase
* Aligns the ink bar to the selected tab on load.
*/
ngAfterContentInit() {
this._realignInkBar = this._ngZone.runOutsideAngular(() => {
let dirChange = this._dir ? this._dir.change : observableOf(null);
let resize = typeof window !== 'undefined' ?
auditTime.call(fromEvent(window, 'resize'), 10) :
observableOf(null);
const dirChange = this._dir ? this._dir.change : observableOf(null);
const resize = typeof window !== 'undefined' ?
auditTime.call(fromEvent(window, 'resize'), 150) :
observableOf(null);
return startWith.call(merge(dirChange, resize), null).subscribe(() => {
this._updatePagination();
this._alignInkBarToSelectedTab();
});
this._realignInkBar = startWith.call(merge(dirChange, resize), null).subscribe(() => {
this._updatePagination();
this._alignInkBarToSelectedTab();
});
}
@@ -215,11 +197,6 @@ export class MdTabHeader extends _MdTabHeaderMixinBase
this._realignInkBar.unsubscribe();
this._realignInkBar = null;
}
if (this._resizeSubscription) {
this._resizeSubscription.unsubscribe();
this._resizeSubscription = null;
}
}
/**
@@ -400,14 +377,18 @@ export class MdTabHeader extends _MdTabHeaderMixinBase
* should be called sparingly.
*/
_checkPaginationEnabled() {
this._showPaginationControls =
const isEnabled =
this._tabList.nativeElement.scrollWidth > this._elementRef.nativeElement.offsetWidth;
if (!this._showPaginationControls) {
if (!isEnabled) {
this.scrollDistance = 0;
}
this._changeDetectorRef.markForCheck();
if (isEnabled !== this._showPaginationControls) {
this._changeDetectorRef.markForCheck();
}
this._showPaginationControls = isEnabled;
}
/**
@@ -441,9 +422,9 @@ export class MdTabHeader extends _MdTabHeaderMixinBase
/** Tells the ink-bar to align itself to the current label wrapper */
private _alignInkBarToSelectedTab(): void {
const selectedLabelWrapper = this._labelWrappers && this._labelWrappers.length
? this._labelWrappers.toArray()[this.selectedIndex].elementRef.nativeElement
: null;
const selectedLabelWrapper = this._labelWrappers && this._labelWrappers.length ?
this._labelWrappers.toArray()[this.selectedIndex].elementRef.nativeElement :
null;
this._inkBar.alignToElement(selectedLabelWrapper);
}