From efda8724535a8560a64b28cc2bf81df5931af686 Mon Sep 17 00:00:00 2001 From: arturovt Date: Thu, 15 May 2025 01:59:33 +0300 Subject: [PATCH] fix(common): prevent reading chunks if app is destroyed (#61354) Prevents processing response chunks after the application has been destroyed. PR Close #61354 --- packages/common/http/src/fetch.ts | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/packages/common/http/src/fetch.ts b/packages/common/http/src/fetch.ts index 631d97519a6..ca19a7f01f5 100644 --- a/packages/common/http/src/fetch.ts +++ b/packages/common/http/src/fetch.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.dev/license */ -import {inject, Injectable, InjectionToken, NgZone} from '@angular/core'; +import {ApplicationRef, inject, Injectable, InjectionToken, NgZone} from '@angular/core'; import {Observable, Observer} from 'rxjs'; import {HttpBackend} from './backend'; @@ -73,6 +73,7 @@ export class FetchBackend implements HttpBackend { private readonly fetchImpl = inject(FetchFactory, {optional: true})?.fetch ?? ((...args) => globalThis.fetch(...args)); private readonly ngZone = inject(NgZone); + private readonly appRef = inject(ApplicationRef); handle(request: HttpRequest): Observable> { return new Observable((observer) => { @@ -152,6 +153,14 @@ export class FetchBackend implements HttpBackend { // Here calling the async ReadableStreamDefaultReader.read() is responsible for triggering CD await this.ngZone.runOutsideAngular(async () => { while (true) { + // Prevent reading chunks if the app is destroyed. Otherwise, we risk doing + // unnecessary work or triggering side effects after teardown. + // This may happen if the app was explicitly destroyed before + // the response returned entirely. + if (this.appRef.destroyed) { + break; + } + const {done, value} = await reader.read(); if (done) {