JAVASCRIPT

Cancel In-Flight API Requests with AbortController

Learn how to use the JavaScript AbortController to cancel ongoing Fetch API requests, preventing unnecessary processing and improving user experience.

let activeAbortController = null; // Store the active controller for cancellation

async function fetchDataWithCancellation(url, customFetch = fetch) {
  // If there's an existing request managed by an AbortController, cancel it
  if (activeAbortController) {
    activeAbortController.abort();
    console.log('Previous request cancelled.');
  }

  // Create a new AbortController for the current request
  activeAbortController = new AbortController();
  const signal = activeAbortController.signal;

  try {
    console.log(`Fetching data from: ${url}`);
    const response = await customFetch(url, { signal });

    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }

    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 fetching data:', error);
    }
    throw error;
  } finally {
    // Clear the controller reference after the request is complete or aborted
    activeAbortController = null;
  }
}

// Example Usage (simulating an API call with a delay):
const searchInput = document.createElement('input');
searchInput.type = 'text';
searchInput.placeholder = 'Type to search...';
document.body.appendChild(searchInput);

const resultDiv = document.createElement('div');
document.body.appendChild(resultDiv);

// Mock fetch function to simulate network delay and AbortController interaction
const mockApiFetch = (url, options) => {
  const signal = options && options.signal;
  return new Promise((resolve, reject) => {
    const timeout = setTimeout(() => {
      if (signal && signal.aborted) {
        console.log(`Mock fetch for ${url} was aborted.`);
        reject(new DOMException('Aborted', 'AbortError'));
        return;
      }
      const query = new URL(url).searchParams.get('q');
      resolve({
        ok: true,
        status: 200,
        json: () => Promise.resolve({ query: query, results: [`Result 1 for "${query}"`, `Result 2 for "${query}"`] }),
      });
    }, Math.random() * 1000 + 500); // Random delay between 0.5s and 1.5s

    if (signal) {
      signal.addEventListener('abort', () => {
        clearTimeout(timeout);
        reject(new DOMException('Aborted', 'AbortError'));
      }, { once: true });
    }
  });
};

searchInput.addEventListener('input', (event) => {
  const query = event.target.value.trim();
  if (query.length < 2) {
    resultDiv.textContent = 'Type at least 2 characters.';
    if (activeAbortController) {
      activeAbortController.abort();
      activeAbortController = null;
    }
    return;
  }

  // Use the function with our mock fetch for demonstration
  fetchDataWithCancellation(`https://api.example.com/search?q=${encodeURIComponent(query)}`, mockApiFetch)
    .then(data => {
      if (!activeAbortController) { // Check if not aborted by a subsequent call
        resultDiv.textContent = JSON.stringify(data, null, 2);
      }
    })
    .catch(error => {
      if (error.name === 'AbortError') {
        resultDiv.textContent = 'Search cancelled.';
      } else {
        resultDiv.textContent = 'Error: ' + error.message;
      }
    });
});

console.log("Type into the search box above to test request cancellation.");
How it works: This JavaScript snippet demonstrates how to use the `AbortController` API to cancel in-flight `fetch` requests. When a new request is initiated (e.g., from rapid user typing in a search box), any previous pending request managed by the shared `activeAbortController` instance is aborted. This is crucial for optimizing frontend performance and user experience by preventing stale or unnecessary data processing and reducing network load.

Need help integrating this into your project?

Our team of expert developers can help you build your custom application from scratch.

Hire DigitalCodeLabs