fix(core): make sure onStable runs in the right zone (#18706)

Make sure the callbacks to the NgZone callbacks run in the right zone
with or without the rxjs Zone patch -
1ed83d08ac.

PR Close #18706
This commit is contained in:
Vikram Subramanian 2017-08-10 17:18:37 -07:00 committed by Miško Hevery
parent 079d884b6c
commit 713d7c2360
2 changed files with 49 additions and 40 deletions

View File

@ -455,17 +455,22 @@ export class ApplicationRef_ extends ApplicationRef {
}); });
const isStable = new Observable<boolean>((observer: Observer<boolean>) => { const isStable = new Observable<boolean>((observer: Observer<boolean>) => {
const stableSub: Subscription = this._zone.onStable.subscribe(() => { // Create the subscription to onStable outside the Angular Zone so that
NgZone.assertNotInAngularZone(); // the callback is run outside the Angular Zone.
let stableSub: Subscription;
this._zone.runOutsideAngular(() => {
stableSub = this._zone.onStable.subscribe(() => {
NgZone.assertNotInAngularZone();
// Check whether there are no pending macro/micro tasks in the next tick // Check whether there are no pending macro/micro tasks in the next tick
// to allow for NgZone to update the state. // to allow for NgZone to update the state.
scheduleMicroTask(() => { scheduleMicroTask(() => {
if (!this._stable && !this._zone.hasPendingMacrotasks && if (!this._stable && !this._zone.hasPendingMacrotasks &&
!this._zone.hasPendingMicrotasks) { !this._zone.hasPendingMicrotasks) {
this._stable = true; this._stable = true;
observer.next(true); observer.next(true);
} }
});
}); });
}); });

View File

@ -62,40 +62,44 @@ export class ComponentFixture<T> {
this.ngZone = ngZone; this.ngZone = ngZone;
if (ngZone) { if (ngZone) {
this._onUnstableSubscription = // Create subscriptions outside the NgZone so that the callbacks run oustide
ngZone.onUnstable.subscribe({next: () => { this._isStable = false; }}); // of NgZone.
this._onMicrotaskEmptySubscription = ngZone.onMicrotaskEmpty.subscribe({ ngZone.runOutsideAngular(() => {
next: () => { this._onUnstableSubscription =
if (this._autoDetect) { ngZone.onUnstable.subscribe({next: () => { this._isStable = false; }});
// Do a change detection run with checkNoChanges set to true to check this._onMicrotaskEmptySubscription = ngZone.onMicrotaskEmpty.subscribe({
// there are no changes on the second run. next: () => {
this.detectChanges(true); if (this._autoDetect) {
// Do a change detection run with checkNoChanges set to true to check
// there are no changes on the second run.
this.detectChanges(true);
}
} }
} });
}); this._onStableSubscription = ngZone.onStable.subscribe({
this._onStableSubscription = ngZone.onStable.subscribe({ next: () => {
next: () => { this._isStable = true;
this._isStable = true; // Check whether there is a pending whenStable() completer to resolve.
// Check whether there is a pending whenStable() completer to resolve. if (this._promise !== null) {
if (this._promise !== null) { // If so check whether there are no pending macrotasks before resolving.
// If so check whether there are no pending macrotasks before resolving. // Do this check in the next tick so that ngZone gets a chance to update the state of
// Do this check in the next tick so that ngZone gets a chance to update the state of // pending macrotasks.
// pending macrotasks. scheduleMicroTask(() => {
scheduleMicroTask(() => { if (!ngZone.hasPendingMacrotasks) {
if (!ngZone.hasPendingMacrotasks) { if (this._promise !== null) {
if (this._promise !== null) { this._resolve !(true);
this._resolve !(true); this._resolve = null;
this._resolve = null; this._promise = null;
this._promise = null; }
} }
} });
}); }
} }
} });
});
this._onErrorSubscription = this._onErrorSubscription =
ngZone.onError.subscribe({next: (error: any) => { throw error; }}); ngZone.onError.subscribe({next: (error: any) => { throw error; }});
});
} }
} }