let currentController = null; // To keep track of the active controller async function fetchDataWithCancellation(url, options = {}) { // If there's an ongoing request, cancel it if (currentController) { console.log('Cancelling previous request...'); currentController.abort(); } // Create a new AbortController for the current request currentController = new AbortController(); const signal = currentController.signal; try { console.log(`Fetching data from: ${url}`); const response = await fetch(url, { ...options, signal }); if (!response.ok) { throw new Error(`HTTP error! Status: ${response.status} - ${response.statusText}`); } const data = await response.json(); console.log('Data fetched successfully:', data); return data; } catch (error) { if (error.name === 'AbortError') { console.warn('Fetch request was aborted.'); } else { console.error('Error during fetch operation:', error); } throw error; } finally { // Clear the controller reference once the request is complete or aborted if (currentController && !currentController.signal.aborted) { currentController = null; } } } // Usage examples: // Simulate a long-running request async function simulateLongRequest() { console.log(' --- Starting a long request ---'); try { const data = await fetchDataWithCancellation('https://jsonplaceholder.typicode.com/posts/1', { // Simulate network delay for testing // Note: fetch API itself doesn't have a direct delay option. // This part would be handled by a real slow API endpoint. // For a demo, you might use a mock fetch or a local server. }); console.log('Long request completed:', data); } catch (e) { // Handled in fetchDataWithCancellation } } // Start a request, then immediately cancel it by starting another async function demonstrateCancellation() { console.log(' --- Demonstrating cancellation ---'); fetchDataWithCancellation('https://jsonplaceholder.typicode.com/todos/1'); // Wait a moment, then start another request, which will cancel the first await new Promise(resolve => setTimeout(resolve, 50)); fetchDataWithCancellation('https://jsonplaceholder.typicode.com/users/1'); // To truly see the abort in action, you'd want a delay long enough for the first // request to *start* but not *finish* before the second one is initiated. // Thejsonplaceholder.typicode.com API is usually fast, so a short timeout works. } simulateLongRequest(); demonstrateCancellation(); // You can also manually abort after some time async function manualAbort() { console.log(' --- Manual abort after delay ---'); try { const controller = new AbortController(); currentController = controller; // Assign for global tracking if desired const signal = controller.signal; const promise = fetch('https://jsonplaceholder.typicode.com/comments/1', { signal }); setTimeout(() => { controller.abort(); console.log('Manually aborted the comments request!'); }, 100); // Abort after 100ms const response = await promise; const data = await response.json(); console.log('Comments data (should not be seen if aborted):', data); } catch (error) { if (error.name === 'AbortError') { console.log('Request was successfully aborted as expected.'); } else { console.error('Error:', error); } } finally { if (currentController && currentController.signal.aborted) { currentController = null; } } } manualAbort();