Skip to content

Commit

Permalink
fix(zone.js): handle fetch with AbortSignal
Browse files Browse the repository at this point in the history
fetch support AbortSignal, zone.js schedules a macroTask when fetch()

```
fetch(..., {signal: abortSignal});
```

we should also be able to cancel fetch with `zoneTask.cancel` call.
So this commit create an internal AbortSignal to handle
`zoneTask.cancel()` call and also delegate the `options.signal` from the
user code.
  • Loading branch information
JiaLiPassion committed Dec 13, 2023
1 parent da86d24 commit 1c4f3cc
Showing 1 changed file with 13 additions and 23 deletions.
36 changes: 13 additions & 23 deletions packages/zone.js/lib/common/fetch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,22 @@ Zone.__load_patch('fetch', (global: any, Zone: ZoneType, api: _ZonePrivate) => {
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 = OriginalAbortController?.prototype[api.symbol('abort')];
const placeholder = function() {};
global['fetch'] = function() {
const args = Array.prototype.slice.call(arguments);
const options = args.length > 1 ? args[1] : null;
const options = args.length > 1 ? args[1] : {};
const signal = options && options.signal;
const ac = new AbortController();
const fetchSignal = ac.signal;
options.signal = fetchSignal;
args[1] = options;
if (signal) {
const nativeAddEventListener =
signal[Zone.__symbol__('addEventListener')] || signal.addEventListener;
nativeAddEventListener.call(signal, 'abort', function() {
ac!.abort();
});
}
return new Promise((res, rej) => {
const task = Zone.current.scheduleMacroTask(
'fetch', placeholder, {fetchArgs: args} as FetchTaskData,
Expand Down Expand Up @@ -72,25 +79,8 @@ Zone.__load_patch('fetch', (global: any, Zone: ZoneType, api: _ZonePrivate) => {
});
},
() => {
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');
}
ac.abort();
});
if (signal && signal.abortController) {
signal.abortController.tasks = [task];
}
});
};
});

0 comments on commit 1c4f3cc

Please sign in to comment.