mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
perf: memory leak when subscribing to zone events (#6918)
Fixes a few memory leaks that were caused by subscribing to `NgZone.onMicrotaskEmpty` or `NgZone.onStable`. Because the two streams are `EventEmitters`, the subscription doesn't get GC-ed correctly. These changes switch to converting the emitters to observables before subscribing to them. Fixes #6905.
This commit is contained in:
committed by
mmalerba
parent
a1ec81ab69
commit
f6c9172afe
@@ -265,7 +265,7 @@ export class FocusTrap {
|
||||
if (this._ngZone.isStable) {
|
||||
fn();
|
||||
} else {
|
||||
first.call(this._ngZone.onStable).subscribe(fn);
|
||||
first.call(this._ngZone.onStable.asObservable()).subscribe(fn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -372,7 +372,7 @@ export class MdAutocompleteTrigger implements ControlValueAccessor, OnDestroy {
|
||||
* stream every time the option list changes.
|
||||
*/
|
||||
private _subscribeToClosingActions(): Subscription {
|
||||
const firstStable = first.call(this._zone.onStable);
|
||||
const firstStable = first.call(this._zone.onStable.asObservable());
|
||||
const optionChanges = map.call(this.autocomplete.options.changes, () =>
|
||||
this._positionStrategy.recalculateLastPosition());
|
||||
|
||||
|
||||
@@ -218,9 +218,11 @@ export class MdCalendar<D> implements AfterContentInit, OnDestroy {
|
||||
|
||||
/** Focuses the active cell after the microtask queue is empty. */
|
||||
_focusActiveCell() {
|
||||
this._ngZone.runOutsideAngular(() => first.call(this._ngZone.onStable).subscribe(() => {
|
||||
this._elementRef.nativeElement.querySelector('.mat-calendar-body-active').focus();
|
||||
}));
|
||||
this._ngZone.runOutsideAngular(() => {
|
||||
first.call(this._ngZone.onStable.asObservable()).subscribe(() => {
|
||||
this._elementRef.nativeElement.querySelector('.mat-calendar-body-active').focus();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/** Whether the two dates represent the same view in the current view mode (month or year). */
|
||||
|
||||
@@ -323,7 +323,9 @@ export class MdDatepicker<D> implements OnDestroy {
|
||||
componentRef.instance.datepicker = this;
|
||||
|
||||
// Update the position once the calendar has rendered.
|
||||
first.call(this._ngZone.onStable).subscribe(() => this._popupRef.updatePosition());
|
||||
first.call(this._ngZone.onStable.asObservable()).subscribe(() => {
|
||||
this._popupRef.updatePosition();
|
||||
});
|
||||
}
|
||||
|
||||
this._popupRef.backdropClick().subscribe(() => this.close());
|
||||
|
||||
@@ -409,8 +409,11 @@ export class MdDrawerContainer implements AfterContentInit, OnDestroy {
|
||||
}
|
||||
// NOTE: We need to wait for the microtask queue to be empty before validating,
|
||||
// since both drawers may be swapping positions at the same time.
|
||||
takeUntil.call(drawer.onPositionChanged, this._drawers.changes).subscribe(() =>
|
||||
first.call(this._ngZone.onMicrotaskEmpty).subscribe(() => this._validateDrawers()));
|
||||
takeUntil.call(drawer.onPositionChanged, this._drawers.changes).subscribe(() => {
|
||||
first.call(this._ngZone.onMicrotaskEmpty.asObservable()).subscribe(() => {
|
||||
this._validateDrawers();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/** Toggles the 'mat-drawer-opened' class on the main 'md-drawer-container' element. */
|
||||
|
||||
@@ -186,13 +186,9 @@ export class MdSnackBarContainer extends BasePortalHost implements OnDestroy {
|
||||
* errors where we end up removing an element which is in the middle of an animation.
|
||||
*/
|
||||
private _completeExit() {
|
||||
// Note: we shouldn't use `this` inside the zone callback,
|
||||
// because it can cause a memory leak.
|
||||
const onExit = this._onExit;
|
||||
|
||||
first.call(this._ngZone.onMicrotaskEmpty).subscribe(() => {
|
||||
onExit.next();
|
||||
onExit.complete();
|
||||
first.call(this._ngZone.onMicrotaskEmpty.asObservable()).subscribe(() => {
|
||||
this._onExit.next();
|
||||
this._onExit.complete();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -392,7 +392,7 @@ export class MdTooltip implements OnDestroy {
|
||||
this._tooltipInstance.message = this.message;
|
||||
this._tooltipInstance._markForCheck();
|
||||
|
||||
first.call(this._ngZone.onMicrotaskEmpty).subscribe(() => {
|
||||
first.call(this._ngZone.onMicrotaskEmpty.asObservable()).subscribe(() => {
|
||||
if (this._tooltipInstance) {
|
||||
this._overlayRef!.updatePosition();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user