MCPcopy
hub / github.com/angular/angular / FetchBackend

Class FetchBackend

packages/common/http/src/fetch.ts:74–417  ·  view source on GitHub ↗

Source from the content-addressed store, hash-verified

72 */
73@Service()
74export class FetchBackend implements HttpBackend {
75 // We use an arrow function to always reference the current global implementation of `fetch`.
76 // This is helpful for cases when the global `fetch` implementation is modified by external code,
77 // see https://github.com/angular/angular/issues/57527.
78 private readonly fetchImpl =
79 inject(FetchFactory, {optional: true})?.fetch ?? ((...args) => globalThis.fetch(...args));
80 private readonly ngZone = inject(NgZone);
81 private readonly destroyRef = inject(DestroyRef);
82 private readonly maxResponseSize = inject(HTTP_FETCH_MAX_RESPONSE_SIZE);
83
84 handle(request: HttpRequest<any>): Observable<HttpEvent<any>> {
85 return new Observable((observer) => {
86 const aborter = new AbortController();
87
88 this.doRequest(request, aborter.signal, observer).then(noop, (error) =>
89 observer.error(new HttpErrorResponse({error})),
90 );
91
92 let timeoutId: ReturnType<typeof setTimeout> | undefined;
93 if (request.timeout) {
94 // TODO: Replace with AbortSignal.any([aborter.signal, AbortSignal.timeout(request.timeout)])
95 // when AbortSignal.any support is Baseline widely available (NET nov. 2026)
96 timeoutId = this.ngZone.runOutsideAngular(() =>
97 setTimeout(() => {
98 if (!aborter.signal.aborted) {
99 aborter.abort(new DOMException('signal timed out', 'TimeoutError'));
100 }
101 }, request.timeout),
102 );
103 }
104
105 return () => {
106 if (timeoutId !== undefined) {
107 clearTimeout(timeoutId);
108 }
109 aborter.abort();
110 };
111 });
112 }
113
114 private async doRequest(
115 request: HttpRequest<any>,
116 signal: AbortSignal,
117 observer: Observer<HttpEvent<any>>,
118 ): Promise<void> {
119 const init = this.createRequestInit(request);
120 let response;
121 try {
122 // Run fetch outside of Angular zone.
123 // This is due to Node.js fetch implementation (Undici) which uses a number of setTimeouts to check if
124 // the response should eventually timeout which causes extra CD cycles every 500ms
125 const fetchPromise = this.ngZone.runOutsideAngular(() =>
126 this.fetchImpl(request.urlWithParams, {signal, ...init}),
127 );
128
129 // Make sure Zone.js doesn't trigger false-positive unhandled promise
130 // error in case the Promise is rejected synchronously. See function
131 // description for additional information.

Callers

nothing calls this directly

Calls 2

injectFunction · 0.90
fetchMethod · 0.45

Tested by

no test coverage detected

Used in the wild real call sites across dependent graphs

searching dependent graphs…