Skip to content

Commit

Permalink
perf(scroll-dispatcher): lazily subscribe to global events
Browse files Browse the repository at this point in the history
Switches the `ScrollDispatcher` to only subscribe to `scroll` and `resize` events if there any registered callbacks. Also unsubscribes once there are no more callbacks.

Fixes angular#3237.
  • Loading branch information
crisbeto committed Feb 23, 2017
1 parent a4da08b commit fae1529
Showing 1 changed file with 16 additions and 6 deletions.
22 changes: 16 additions & 6 deletions src/lib/core/overlay/scroll/scroll-dispatcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {Subject} from 'rxjs/Subject';
import {Observable} from 'rxjs/Observable';
import {Subscription} from 'rxjs/Subscription';
import 'rxjs/add/observable/fromEvent';
import 'rxjs/add/observable/merge';
import 'rxjs/add/operator/auditTime';


Expand All @@ -19,18 +20,15 @@ export class ScrollDispatcher {
/** Subject for notifying that a registered scrollable reference element has been scrolled. */
_scrolled: Subject<void> = new Subject<void>();

/** Keeps track of the global `scroll` and `resize` subscriptions. */
private _globalSubscription: Subscription;

/**
* Map of all the scrollable references that are registered with the service and their
* scroll event subscriptions.
*/
scrollableReferences: Map<Scrollable, Subscription> = new Map();

constructor() {
// By default, notify a scroll event when the document is scrolled or the window is resized.
Observable.fromEvent(window.document, 'scroll').subscribe(() => this._notify());
Observable.fromEvent(window, 'resize').subscribe(() => this._notify());
}

/**
* Registers a Scrollable with the service and listens for its scrolled events. When the
* scrollable is scrolled, the service emits the event in its scrolled observable.
Expand All @@ -39,6 +37,13 @@ export class ScrollDispatcher {
register(scrollable: Scrollable): void {
const scrollSubscription = scrollable.elementScrolled().subscribe(() => this._notify());
this.scrollableReferences.set(scrollable, scrollSubscription);

if (!this._globalSubscription) {
this._globalSubscription = Observable.merge(
Observable.fromEvent(window.document, 'scroll'),
Observable.fromEvent(window, 'resize')
).subscribe(() => this._notify());
}
}

/**
Expand All @@ -49,6 +54,11 @@ export class ScrollDispatcher {
if (this.scrollableReferences.has(scrollable)) {
this.scrollableReferences.get(scrollable).unsubscribe();
this.scrollableReferences.delete(scrollable);

if (!this.scrollableReferences.size && this._globalSubscription) {
this._globalSubscription.unsubscribe();
this._globalSubscription = null;
}
}
}

Expand Down

0 comments on commit fae1529

Please sign in to comment.