Skip to content

Commit

Permalink
perf(tabs): avoid extra resize handler and reflow (#6434)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
crisbeto authored and andrewseguin committed Aug 15, 2017
1 parent 5d437ea commit 1df79e9
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 40 deletions.
2 changes: 1 addition & 1 deletion src/lib/tabs/tab-header.spec.ts
Expand Up @@ -259,7 +259,7 @@ describe('MdTabHeader', () => {
spyOn(inkBar, 'alignToElement');

dispatchFakeEvent(window, 'resize');
tick(10);
tick(150);
fixture.detectChanges();

expect(inkBar.alignToElement).toHaveBeenCalled();
Expand Down
59 changes: 20 additions & 39 deletions src/lib/tabs/tab-header.ts
Expand Up @@ -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';
Expand All @@ -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'
Expand Down Expand Up @@ -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;
}
Expand All @@ -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 {
Expand Down Expand Up @@ -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);

return startWith.call(merge(dirChange, resize), null).subscribe(() => {
this._updatePagination();
this._alignInkBarToSelectedTab();
});
const dirChange = this._dir ? this._dir.change : observableOf(null);
const resize = typeof window !== 'undefined' ?
auditTime.call(fromEvent(window, 'resize'), 150) :
observableOf(null);

this._realignInkBar = startWith.call(merge(dirChange, resize), null).subscribe(() => {
this._updatePagination();
this._alignInkBarToSelectedTab();
});
}

Expand All @@ -215,11 +197,6 @@ export class MdTabHeader extends _MdTabHeaderMixinBase
this._realignInkBar.unsubscribe();
this._realignInkBar = null;
}

if (this._resizeSubscription) {
this._resizeSubscription.unsubscribe();
this._resizeSubscription = null;
}
}

/**
Expand Down Expand Up @@ -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;
}

/**
Expand Down Expand Up @@ -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);
}
Expand Down

0 comments on commit 1df79e9

Please sign in to comment.