fix(core): unsubscribe from the `onError` when the root view is removed (#39940)
At the moment, when creating a root module, a subscription to the `onError` subject is also created. It captures the scope where `NgModuleRef` is created and prevents it from being garbage collected. Also note that this `NgModuleRef` has a reference to the root module instance (e.g. `AppModule`), which also prevents it from being GC'd. PR Close #39940
This commit is contained in:
parent
f01c713ee2
commit
5a3a154cd8
|
@ -350,12 +350,17 @@ export class PlatformRef {
|
|||
if (!exceptionHandler) {
|
||||
throw new Error('No ErrorHandler. Is platform module (BrowserModule) included?');
|
||||
}
|
||||
moduleRef.onDestroy(() => remove(this._modules, moduleRef));
|
||||
ngZone!.runOutsideAngular(() => ngZone!.onError.subscribe({
|
||||
next: (error: any) => {
|
||||
exceptionHandler.handleError(error);
|
||||
}
|
||||
}));
|
||||
ngZone!.runOutsideAngular(() => {
|
||||
const subscription = ngZone!.onError.subscribe({
|
||||
next: (error: any) => {
|
||||
exceptionHandler.handleError(error);
|
||||
}
|
||||
});
|
||||
moduleRef.onDestroy(() => {
|
||||
remove(this._modules, moduleRef);
|
||||
subscription.unsubscribe();
|
||||
});
|
||||
});
|
||||
return _callAndReportToErrorHandler(exceptionHandler, ngZone!, () => {
|
||||
const initStatus: ApplicationInitStatus = moduleRef.injector.get(ApplicationInitStatus);
|
||||
initStatus.runInitializers();
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {ApplicationRef, COMPILER_OPTIONS, Component, destroyPlatform, NgModule, TestabilityRegistry, ViewEncapsulation} from '@angular/core';
|
||||
import {ApplicationRef, COMPILER_OPTIONS, Component, destroyPlatform, NgModule, NgZone, TestabilityRegistry, ViewEncapsulation} from '@angular/core';
|
||||
import {expect} from '@angular/core/testing/src/testing_internal';
|
||||
import {BrowserModule} from '@angular/platform-browser';
|
||||
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
|
||||
|
@ -227,6 +227,22 @@ describe('bootstrap', () => {
|
|||
}));
|
||||
});
|
||||
|
||||
describe('PlatformRef cleanup', () => {
|
||||
it('should unsubscribe from `onError` when Injector is destroyed',
|
||||
withBody('<my-app></my-app>', async () => {
|
||||
const TestModule = createComponentAndModule();
|
||||
|
||||
const ngModuleRef = await platformBrowserDynamic().bootstrapModule(TestModule);
|
||||
const ngZone = ngModuleRef.injector.get(NgZone);
|
||||
|
||||
expect(ngZone.onError.observers.length).toBe(1);
|
||||
|
||||
ngModuleRef.destroy();
|
||||
|
||||
expect(ngZone.onError.observers.length).toBe(0);
|
||||
}));
|
||||
});
|
||||
|
||||
onlyInIvy('options cannot be changed in Ivy').describe('changing bootstrap options', () => {
|
||||
beforeEach(() => {
|
||||
spyOn(console, 'error');
|
||||
|
@ -365,4 +381,4 @@ export class MultipleSelectorsAppComponent {
|
|||
bootstrap: [MultipleSelectorsAppComponent],
|
||||
})
|
||||
export class MultipleSelectorsAppModule {
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue