From fc4303658da590e4e84b705efcf7a76e104a2693 Mon Sep 17 00:00:00 2001 From: ekzyis Date: Fri, 13 Dec 2024 15:38:42 +0100 Subject: [PATCH] Use AbortSignal.timeout + custom timeout error message (#1718) * refactor: replace custom logic with AbortSignal.timeout * Use custom timeout error message * Include method and url in fetch timeout error * Fix error not rethrown --- lib/fetch.js | 32 ++++++++++++++++++++++---------- lib/time.js | 7 +++++++ 2 files changed, 29 insertions(+), 10 deletions(-) diff --git a/lib/fetch.js b/lib/fetch.js index 2b3ed330..918e8623 100644 --- a/lib/fetch.js +++ b/lib/fetch.js @@ -1,14 +1,26 @@ +import { TimeoutError } from '@/lib/time' + +class FetchTimeoutError extends TimeoutError { + constructor (method, url, timeout) { + super(timeout) + this.name = 'FetchTimeoutError' + this.message = `${method} ${url}: timeout after ${timeout / 1000}s` + } +} + export async function fetchWithTimeout (resource, { timeout = 1000, ...options } = {}) { - const controller = new AbortController() - const id = setTimeout(() => controller.abort(), timeout) - - const response = await fetch(resource, { - ...options, - signal: controller.signal - }) - clearTimeout(id) - - return response + try { + return await fetch(resource, { + ...options, + signal: AbortSignal.timeout(timeout) + }) + } catch (err) { + if (err.name === 'TimeoutError') { + // use custom error message + throw new FetchTimeoutError('GET', resource, timeout) + } + throw err + } } class LRUCache { diff --git a/lib/time.js b/lib/time.js index 22589c6b..2f3c6c30 100644 --- a/lib/time.js +++ b/lib/time.js @@ -128,6 +128,13 @@ function tzOffset (tz) { return targetOffsetHours } +export class TimeoutError extends Error { + constructor (timeout) { + super(`timeout after ${timeout / 1000}s`) + this.name = 'TimeoutError' + } +} + function timeoutPromise (timeout) { return new Promise((resolve, reject) => { // if no timeout is specified, never settle