/** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ /** * @fileoverview * @suppress {missingRequire} */ Zone.__load_patch('fetch', (global: any, Zone: ZoneType, api: _ZonePrivate) => { interface FetchTaskData extends TaskData { fetchArgs?: any[]; } let fetch = global['fetch']; if (typeof fetch !== 'function') { return; } const originalFetch = global[api.symbol('fetch')]; if (originalFetch) { // restore unpatched fetch first fetch = originalFetch; } const ZoneAwarePromise = global.Promise; const symbolThenPatched = api.symbol('thenPatched'); const fetchTaskScheduling = api.symbol('fetchTaskScheduling'); const fetchTaskAborting = api.symbol('fetchTaskAborting'); const OriginalAbortController = global['AbortController']; const supportAbort = typeof OriginalAbortController === 'function'; let abortNative: Function|null = null; if (supportAbort) { global['AbortController'] = function() { const abortController = new OriginalAbortController(); const signal = abortController.signal; signal.abortController = abortController; return abortController; }; abortNative = api.patchMethod( OriginalAbortController.prototype, 'abort', (delegate: Function) => (self: any, args: any) => { if (self.task) { return self.task.zone.cancelTask(self.task); } return delegate.apply(self, args); }); } const placeholder = function() {}; global['fetch'] = function() { const args = Array.prototype.slice.call(arguments); const options = args.length > 1 ? args[1] : null; const signal = options && options.signal; return new Promise((res, rej) => { const task = Zone.current.scheduleMacroTask( 'fetch', placeholder, {fetchArgs: args} as FetchTaskData, () => { let fetchPromise; let zone = Zone.current; try { (zone as any)[fetchTaskScheduling] = true; fetchPromise = fetch.apply(this, args); } catch (error) { rej(error); return; } finally { (zone as any)[fetchTaskScheduling] = false; } if (!(fetchPromise instanceof ZoneAwarePromise)) { let ctor = fetchPromise.constructor; if (!ctor[symbolThenPatched]) { api.patchThen(ctor); } } fetchPromise.then( (resource: any) => { if (task.state !== 'notScheduled') { task.invoke(); } res(resource); }, (error: any) => { if (task.state !== 'notScheduled') { task.invoke(); } rej(error); }); }, () => { if (!supportAbort) { rej('No AbortController supported, can not cancel fetch'); return; } if (signal && signal.abortController && !signal.aborted && typeof signal.abortController.abort === 'function' && abortNative) { try { (Zone.current as any)[fetchTaskAborting] = true; abortNative.call(signal.abortController); } finally { (Zone.current as any)[fetchTaskAborting] = false; } } else { rej('cancel fetch need a AbortController.signal'); } }); if (signal && signal.abortController) { signal.abortController.task = task; } }); }; });