Skip to content

Commit

Permalink
chore: read abort signal in fetchWithTimeout
Browse files Browse the repository at this point in the history
  • Loading branch information
micaelae committed Oct 23, 2024
1 parent ba775a2 commit db1d225
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 2 deletions.
17 changes: 17 additions & 0 deletions shared/modules/fetch-with-timeout.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,23 @@ describe('getFetchWithTimeout', () => {
}).rejects.toThrow('The user aborted a request.');
});

it('should abort the request when a custom signal aborts', async () => {
nock('https://api.infura.io')
.get('/moon')
.delay(SECOND * 2)
.reply(200, '{"moon": "2012-12-21T11:11:11Z"}');
const abortSignal = new window.AbortController();

const fetchWithTimeout = getFetchWithTimeout(SECOND * 30);

setTimeout(() => abortSignal.abort('Request aborted'), SECOND * 2);
await expect(async () => {
await fetchWithTimeout('https://api.infura.io/moon', {
signal: abortSignal.signal,
}).then((r) => r.json());
}).rejects.toThrow('The user aborted a request.');
});

it('throws on invalid timeout', async () => {
await expect(() => getFetchWithTimeout(-1)).toThrow(
'Must specify positive integer timeout.',
Expand Down
17 changes: 15 additions & 2 deletions shared/modules/fetch-with-timeout.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,20 @@ const getFetchWithTimeout = memoize((timeout = SECOND * 30) => {
opts?: RequestInit,
): Promise<Response> {
const abortController = new window.AbortController();
const { signal } = abortController;

// Add the provided signal to the list of signals that can abort the request
const abortSignals = [abortController.signal];
if (opts?.signal) {
abortSignals.push(opts.signal);
}

const combinedAbortController = new AbortController();
const abortHandler = () => combinedAbortController.abort();
abortSignals.forEach((sig) => sig.addEventListener('abort', abortHandler));

const f = window.fetch(url, {
...opts,
signal,
signal: combinedAbortController.signal,
});

const timer = setTimeout(() => abortController.abort(), timeout);
Expand All @@ -33,6 +43,9 @@ const getFetchWithTimeout = memoize((timeout = SECOND * 30) => {
return await f;
} finally {
clearTimeout(timer);
abortSignals.forEach((sig) =>
sig.removeEventListener('abort', abortHandler),
);
}
};
});
Expand Down

0 comments on commit db1d225

Please sign in to comment.