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;
 | |
|       }
 | |
|     });
 | |
|   };
 | |
| });
 |