fix(service-worker): remove controllerchange listener when app is destroyed (#55365)

This commit updates the `ngswAppInitializer` implementation and removes the `controllerchange`
listener upon the destruction of the `ApplicationRef`. This adjustment aims to prevent memory
leaks. In a zone.js environment, neglecting to do so could lead to the perpetual creation of
a zone task, which captures the zone and obstructs proper garbage collection.

PR Close #55365
This commit is contained in:
arturovt 2024-04-16 19:10:47 +03:00 committed by Dylan Hunn
parent a5512d3c4b
commit afe45616ad
2 changed files with 18 additions and 6 deletions

View file

@ -40,6 +40,7 @@ export function ngswAppInitializer(
}
const ngZone = injector.get(NgZone);
const appRef = injector.get(ApplicationRef);
// Set up the `controllerchange` event listener outside of
// the Angular zone to avoid unnecessary change detections,
@ -48,10 +49,13 @@ export function ngswAppInitializer(
// Wait for service worker controller changes, and fire an INITIALIZE action when a new SW
// becomes active. This allows the SW to initialize itself even if there is no application
// traffic.
navigator.serviceWorker.addEventListener('controllerchange', () => {
if (navigator.serviceWorker.controller !== null) {
navigator.serviceWorker.controller.postMessage({action: 'INITIALIZE'});
}
const sw = navigator.serviceWorker;
const onControllerChange = () => sw.controller?.postMessage({action: 'INITIALIZE'});
sw.addEventListener('controllerchange', onControllerChange);
appRef.onDestroy(() => {
sw.removeEventListener('controllerchange', onControllerChange);
});
});

View file

@ -168,7 +168,11 @@ const serviceWorkerModuleApi = 'ServiceWorkerModule';
provideServiceWorker('sw.js'),
{
provide: ApplicationRef,
useValue: {isStable: isStableSub.asObservable(), afterTick: new Subject()},
useValue: {
isStable: isStableSub.asObservable(),
afterTick: new Subject(),
onDestroy: () => {},
},
},
{provide: PLATFORM_ID, useValue: 'browser'},
{
@ -183,7 +187,11 @@ const serviceWorkerModuleApi = 'ServiceWorkerModule';
providers: [
{
provide: ApplicationRef,
useValue: {isStable: isStableSub.asObservable(), afterTick: new Subject()},
useValue: {
isStable: isStableSub.asObservable(),
afterTick: new Subject(),
onDestroy: () => {},
},
},
{provide: PLATFORM_ID, useValue: 'browser'},
{