From bb042c1501158394cc22cfadaa012fa276aec77e Mon Sep 17 00:00:00 2001 From: crisbeto Date: Mon, 21 May 2018 11:06:38 +0200 Subject: [PATCH] perf(overlay): only compute and emit position changes if there are subscribers When emitting the `ConnectedOverlayPositionChange`, we have to compute whether the overlay is being clipped by the viewport or one of its parent scrollables. These calculations can be expensive, because they need the `ClientRect` of each element, however they won't necessarily be used by the consumer. These changes move things around so we only calculate the scrollable clipping if the consumer has subscribed to the `positionChanges` observable. --- .../flexible-connected-position-strategy.ts | 25 +++++++++++++++---- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/src/cdk/overlay/position/flexible-connected-position-strategy.ts b/src/cdk/overlay/position/flexible-connected-position-strategy.ts index e0604d8f1309..0786f1ff81ef 100644 --- a/src/cdk/overlay/position/flexible-connected-position-strategy.ts +++ b/src/cdk/overlay/position/flexible-connected-position-strategy.ts @@ -108,9 +108,19 @@ export class FlexibleConnectedPositionStrategy implements PositionStrategy { /** Selector to be used when finding the elements on which to set the transform origin. */ private _transformOriginSelector: string; + /** Amount of subscribers to the `positionChanges` stream. */ + private _positionChangeSubscriptions = 0; + /** Observable sequence of position changes. */ - positionChanges: Observable = - this._positionChanges.asObservable(); + positionChanges: Observable = Observable.create(observer => { + const subscription = this._positionChanges.subscribe(observer); + this._positionChangeSubscriptions++; + + return () => { + subscription.unsubscribe(); + this._positionChangeSubscriptions--; + }; + }); /** Ordered list of preferred positions, from most to least desirable. */ get positions() { @@ -581,9 +591,14 @@ export class FlexibleConnectedPositionStrategy implements PositionStrategy { this._lastPosition = position; // Notify that the position has been changed along with its change properties. - const scrollableViewProperties = this._getScrollVisibility(); - const changeEvent = new ConnectedOverlayPositionChange(position, scrollableViewProperties); - this._positionChanges.next(changeEvent); + // We only emit if we've got any subscriptions, because the scroll visibility + // calculcations can be somewhat expensive. + if (this._positionChangeSubscriptions > 0) { + const scrollableViewProperties = this._getScrollVisibility(); + const changeEvent = new ConnectedOverlayPositionChange(position, scrollableViewProperties); + this._positionChanges.next(changeEvent); + } + this._isInitialRender = false; }