AJAX

JavaScript Fetch with Timeout Gets a Modern Upgrade

Network requests hang. Servers go silent, APIs stall, and your code waits forever. You need a way to cancel requests that take too long—and modern JavaScript finally gives you proper tools to do exactly that.

The fetch API now works with AbortController and AbortSignal to make timeout handling clean and reliable. A developer walkthrough on davidwalsh.name shows exactly how this works.

At a Glance

  • AbortSignal.timeout() auto-aborts a request after a set number of milliseconds
  • AbortController pairs with setTimeout for broader browser support
  • Signals attach directly to fetch() for automatic cancellation
  • Browser support for AbortSignal.timeout() is growing but not yet universal
  • Both approaches properly clean up timers when requests finish

The Modern Way: AbortSignal.timeout()

“`javascript

Async function fetchWithTimeout(url, opts = {}, timeout = 5000) {

Const signal = AbortSignal.timeout(timeout);

Const response = await fetch(url, { …opts, signal });

Return response;

}

“`

Attach the signal to your fetch options and the request cancels itself after the timeout. Your code catches the resulting AbortError just like any other error.

The Compatible Way: AbortController + setTimeout

“`javascript

Async function fetchWithTimeout(url, opts = {}, timeout = 5000) {

Const controller = new AbortController();

Const signal = controller.signal;

Const timer = setTimeout(() => controller.abort(), timeout);

Try {

Const response = await fetch(url, { …opts, signal });

ClearTimeout(timer);

Return response;

} catch (e) {

ClearTimeout(timer);

Throw e;

}

}

“`

The manual timer approach clears the timeout when the request succeeds and also clears it in the catch block. This prevents memory leaks from abandoned timers.

Why This Matters

AbortController and AbortSignal have matured into a proper cancellation API. The old Promise.race() workaround left timers running even after requests completed—technically a memory leak, practically a source of subtle bugs.

The signal-based approach ties the request directly to its cancellation. When the signal aborts, the fetch rejects immediately. No orphaned timers, no race conditions between success and timeout.

Beyond simple timeouts, these APIs enable other patterns: cancelling requests when a user navigates away, deduplicating concurrent requests, or coordinating groups of related fetches.

A Practical Example

Say you're building a dashboard that fetches data from multiple endpoints. Some respond instantly, others crawl. Instead of letting slow endpoints block your UI, you wrap each fetch:

“`javascript

Const endpoints = [

'/api/stats',

'/api/notifications',

'/api/user-profile'

];

Const results = await Promise.all(

Endpoints.map(url => fetchWithTimeout(url, {}, 3000))

);

“`

Requests that finish within 3 seconds succeed. Everything else gets cancelled. Your dashboard renders with whatever data arrived in time.

Bottom Line

Use AbortSignal.timeout() when you can rely on modern browser support. Fall back to AbortController with setTimeout for wider compatibility. Either way, stop leaving fetch requests unthrottled. If your code still uses Promise.race() for timeouts, this is a clean upgrade worth making.

Key takeaways

  • AbortSignal.timeout() is the cleanest option for new projects targeting modern browsers
  • AbortController with manual setTimeout covers browsers that don't yet support AbortSignal.timeout()
  • Always clear your timers in both success and error paths
  • This pattern scales to cancelling multiple related requests together

Frequently asked questions

What happens when a fetch times out?

The fetch promise rejects with an AbortError, which you can catch and handle like any other error.

Which browsers support AbortSignal.timeout()?

Currently only the latest Edge browser versions support it. For production code, the AbortController approach is safer.

Can I use this with POST requests?

Yes. The signal attaches to the fetch regardless of HTTP method. The timeout applies to the entire request-response cycle.

Does this work in Node.js?

The AbortController API is available in Node.js 15.x and later, but browser implementations may differ.

Can I cancel a request without a timeout?

Yes. Call controller.abort() manually whenever you want to cancel—navigation events, user actions, or request deduplication are all valid reasons.

Related