113 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
		
		
			
		
	
	
			113 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
|  | /** | ||
|  |  * @license | ||
|  |  * Copyright Google Inc. 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; | ||
|  |       } | ||
|  |     }); | ||
|  |   }; | ||
|  | }); |