AbortController | Cancel a Promise | Cancel Events | Cancel Timeouts | Cancel APIs
๐น 1. What is AbortController
in JavaScript?
Answer:
AbortController
is a built-in browser API used to abort ongoing asynchronous operations, especially fetch()
requests.
const controller = new AbortController(); const signal = controller.signal; fetch('https://api.example.com/data', { signal }) .then(response => response.json()) .catch(err => { if (err.name === 'AbortError') { console.log('Fetch aborted'); } else { console.error(err); } }); controller.abort(); // Cancels the fetch
โ Used to cancel requests or operations with cleanup logic.
๐น 2. What is AbortSignal
?
Answer:
AbortSignal
is a property of AbortController
that gets passed to the request (e.g., fetch
). It's used to monitor the status of the operation and detect if it was aborted.
const controller = new AbortController(); const signal = controller.signal; signal.addEventListener('abort', () => { console.log('Operation was aborted!'); });
๐น 3. Can you cancel a Promise in JavaScript?
Answer:
No, JavaScript does not natively support canceling Promises once started. But we can implement a pattern using AbortController
or custom logic to simulate cancellation.
Custom cancelable promise:
function cancelablePromise(promise) { let cancel; const wrapped = new Promise((resolve, reject) => { cancel = () => reject('Cancelled'); promise.then(resolve).catch(reject); }); return [wrapped, cancel]; } const [promise, cancel] = cancelablePromise(fetch('https://api.example.com')); cancel(); // Cancels it
๐น 4. How to cancel a fetch request in JavaScript?
Answer:
Use AbortController
.
const controller = new AbortController(); fetch('/api/data', { signal: controller.signal }); controller.abort(); // Cancels the fetch
๐น 5. How do you cancel event listeners in JavaScript?
Answer:
Use removeEventListener
.
function handleClick() { console.log('Clicked'); } document.addEventListener('click', handleClick); document.removeEventListener('click', handleClick); // Cancels it
โ Always keep a reference to the function to remove it.
๐น 6. How to cancel a setTimeout
in JavaScript?
Answer:
Use clearTimeout
.
const timeout = setTimeout(() => { console.log('Hello after 2s'); }, 2000); clearTimeout(timeout); // Cancels the timeout
๐น 7. How to cancel a setInterval
in JavaScript?
Answer:
Use clearInterval
.
const interval = setInterval(() => { console.log('Tick'); }, 1000); clearInterval(interval); // Stops the interval
๐น 8. Can AbortController
be reused?
Answer:
No, once abort()
is called, the controller becomes permanently aborted. You need a new instance to control another request.
๐น 9. How to cancel multiple fetches using one AbortController?
Answer:
You can pass the same AbortSignal
to multiple fetch requests.
const controller = new AbortController(); const signal = controller.signal; fetch('/api/1', { signal }); fetch('/api/2', { signal }); controller.abort(); // Cancels both
๐น 10. Use case: Cancel search API requests on input typing
Answer:
let controller; function onSearchInput(e) { if (controller) controller.abort(); // Cancel previous controller = new AbortController(); fetch(`/search?q=${e.target.value}`, { signal: controller.signal }) .then(res => res.json()) .then(data => console.log(data)) .catch(err => { if (err.name !== 'AbortError') { console.error(err); } }); }
๐น 11. How do you cancel async operations like file uploads or streams?
Answer:
Depends on the API. Use AbortController
or internal flags in custom implementations.
๐น 12. What happens if you call abort()
after the request has completed?
Answer: Nothing. The controller will do nothing since the request is already resolved.
๐น 13. Difference between AbortController
and custom cancel logic?
Feature | AbortController | Custom Cancel Logic |
---|---|---|
Native Support | Yes (browser API) | No (manual implementation) |
Used For | fetch , streams, etc. | Any async operation |
Cleanup Hook | Yes (abort event) | Needs manual setup |
Reusability | No | You control reuse manually |
๐น 14. Can we use AbortController in Node.js?
Answer:
Yes, from Node.js v15+, AbortController
is available and supported in fetch
, stream
, fs
, etc.
import fetch from 'node-fetch'; const controller = new AbortController(); fetch('https://api.example.com', { signal: controller.signal }); controller.abort();
๐น 15. What other browser APIs support AbortController?
Answer:
fetch()
ReadableStream
WritableStream
FileReader
WebSocket
(partially with polyfills)navigator.sendBeacon()
(limited use)- Some DOM Events (via libraries or custom abstraction)
๐ธ 16. Can you cancel setTimeout
using AbortController
?
Answer:
Yes, you can build a utility that cancels a setTimeout
using AbortController
.
function setAbortableTimeout(fn, delay, signal) { const id = setTimeout(() => { if (!signal.aborted) fn(); }, delay); signal.addEventListener('abort', () => { clearTimeout(id); }); } // Usage const controller = new AbortController(); setAbortableTimeout(() => console.log('Runs in 2s'), 2000, controller.signal); controller.abort(); // Cancels the timeout
โ
This simulates timeout cancellation via AbortController
.
๐ธ 17. How to cancel setTimeout
in React using useRef
?
Answer:
In React, useRef
is commonly used to store the timeout ID to clean it up.
import { useEffect, useRef } from 'react'; function MyComponent() { const timeoutRef = useRef<number | null>(null); useEffect(() => { timeoutRef.current = window.setTimeout(() => { console.log('Runs in 3s'); }, 3000); return () => { if (timeoutRef.current) { clearTimeout(timeoutRef.current); } }; }, []); return <div>MyComponent</div>; }
โ This is a React-friendly way to cancel timeout on unmount or re-render.
๐ธ 18. Alternative to removeEventListener
using AbortController
Answer:
You can pass an AbortSignal
when adding the event listener, and it will automatically remove itself when aborted:
const controller = new AbortController(); window.addEventListener('click', () => { console.log('clicked!'); }, { signal: controller.signal }); controller.abort(); // Automatically removes the event listener
โ
This is a clean alternative to manually using removeEventListener
.
๐ธ 19. Canceling Event Listeners in React?
Answer:
In React, useEffect
and useRef
are commonly used:
import { useEffect } from 'react'; function MyComponent() { useEffect(() => { const handleClick = () => console.log('clicked'); window.addEventListener('click', handleClick); return () => { window.removeEventListener('click', handleClick); // Clean up }; }, []); return <div>Click anywhere</div>; }
Or with AbortController (experimental, works in modern browsers):
useEffect(() => { const controller = new AbortController(); window.addEventListener('click', () => { console.log('clicked'); }, { signal: controller.signal }); return () => controller.abort(); // Auto cleanup }, []);
๐ง Bonus Interview Questions
๐ธ 20. Whatโs better: AbortController or useRef with clearTimeout?
Answer:
Use Case | Best Tool |
---|---|
Timeouts inside components | useRef + clearTimeout |
Complex abort logic across modules | AbortController |
Multiple listeners | AbortController with signal |
Legacy support needed | useRef or manual cleanup |
Use both where appropriate. Combine them for best results in complex apps.
๐ธ 21. Can we use useRef.current.abort()
to cancel operations in React?
Answer:
Yes! You can use useRef
to persist the AbortController
across renders and call .abort()
in cleanup functions like useEffect
.
This is a React pattern for managing cancellable side effects.
โ Example: Cancel API Request on Component Unmount
import { useEffect, useRef } from 'react'; function MyComponent() { const abortControllerRef = useRef<AbortController | null>(null); useEffect(() => { abortControllerRef.current = new AbortController(); fetch('https://api.example.com/data', { signal: abortControllerRef.current.signal, }) .then(res => res.json()) .then(data => console.log(data)) .catch(err => { if (err.name === 'AbortError') { console.log('Fetch aborted'); } else { console.error(err); } }); return () => { abortControllerRef.current?.abort(); // Cancel the fetch on unmount }; }, []); return <div>Data Loading...</div>; }
๐ธ 22. Why use useRef
for AbortController
in React?
Answer:
useRef
stores a persistent mutable object across renders.- Useful to store a controller that doesn't change when component re-renders.
- Avoids triggering re-renders unlike
useState
.
โ
Ideal for aborting fetches or timers in useEffect
.
๐ธ 23. What happens if useRef.current.abort()
is called twice?
Answer:
Calling .abort()
multiple times is harmless. The second and further calls do nothing. Once aborted, the controller is in the "aborted" state permanently.
๐ธ 24. Can I reuse useRef.current.signal
for a new fetch?
Answer: โ No. Once aborted, the signal is permanently aborted.
โ
To reuse, you must create a new AbortController
:
abortControllerRef.current = new AbortController(); // Replace the old one
๐ธ 25. How do you cancel previous API requests in search input (React)?
Answer:
function SearchComponent() { const abortRef = useRef<AbortController | null>(null); const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => { if (abortRef.current) { abortRef.current.abort(); // Cancel previous } abortRef.current = new AbortController(); fetch(`/api/search?q=${e.target.value}`, { signal: abortRef.current.signal, }) .then(res => res.json()) .then(data => console.log(data)) .catch(err => { if (err.name !== 'AbortError') console.error(err); }); }; return <input type="text" onChange={handleInputChange} />; }
โ This ensures only the latest input triggers the search.
๐ธ 26. When should you avoid using AbortController
with useRef
?
Answer:
- Donโt use it for simple timeouts โ prefer
setTimeout
+useRef
. - Donโt store it if you only use
fetch
once. - Avoid if you donโt need to cancel anything.
Use it when:
- You need to cancel API requests
- You handle dynamic updates (e.g., user typing)
- You want cleanup on unmount
๐ธ 27. Is useRef.current.abort()
better than clearTimeout()
?
Answer: They're for different use cases:
Feature | useRef + clearTimeout | useRef + AbortController |
---|---|---|
For timers | โ Yes | โ No |
For canceling fetch/API | โ No | โ Yes |
Can listen to abort | โ No | โ
Yes (via .signal ) |
Browser-native canceling | โ Manual | โ
Native with fetch |
Use each where it makes the most sense.