From fae1529e64f8e535fe60bbd6d4c5b0b8d517f877 Mon Sep 17 00:00:00 2001 From: crisbeto Date: Thu, 23 Feb 2017 21:44:25 +0100 Subject: [PATCH] perf(scroll-dispatcher): lazily subscribe to global events 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 #3237. --- .../core/overlay/scroll/scroll-dispatcher.ts | 22 ++++++++++++++----- 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/lib/core/overlay/scroll/scroll-dispatcher.ts b/src/lib/core/overlay/scroll/scroll-dispatcher.ts index 334ebabfa37e..6edb0e982507 100644 --- a/src/lib/core/overlay/scroll/scroll-dispatcher.ts +++ b/src/lib/core/overlay/scroll/scroll-dispatcher.ts @@ -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'; @@ -19,18 +20,15 @@ export class ScrollDispatcher { /** Subject for notifying that a registered scrollable reference element has been scrolled. */ _scrolled: Subject = new Subject(); + /** 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 = 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. @@ -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()); + } } /** @@ -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; + } } }