My users were complaining that typing fast into our dashboard search bar sometimes showed completely wrong results. A search for 'banana' would briefly flash results for 'apple' because the slower network request finished after the faster one.
Here is what you will learn in this post:
- How race conditions happen in asynchronous front-end applications.
- Why standard debouncing does not completely solve overlapping API requests.
- How to use Axios CancelTokens in Vue.js to abort stale HTTP requests.
- How to handle request cancellation cleanly in a Laravel API controller.
What the Bug Looked Like to the User
To the user, the app felt glitchy and untrustworthy. If they typed 'cat' quickly and then 'dog', the 'cat' query would sometimes hit the server last and overwrite the 'dog' results on the screen.
This happens because network requests do not always return in the order you send them. A heavier database query might take longer, even if it was sent first.
How I Diagnosed the Problem Step by Step
I opened the Network tab in my browser developer tools and throttled my connection to 'Fast 3G'. Then I typed a few letters quickly into the search input.
I watched three distinct requests fire off to our Laravel backend endpoint. The third request finished first, then the second, and finally the first request finished and wiped out the correct data.
The Actual Fix with Code
The fix is to cancel any pending search request before sending a new one. Here is how I updated the Vue.js component using Axios cancel tokens, which are built-in objects used to abort HTTP requests.
let cancelToken = null;
async function performSearch(query) {
if (cancelToken) {
cancelToken.cancel('Operation canceled due to new request.');
}
cancelToken = axios.CancelToken.source();
try {
const response = await axios.get('/api/search', {
params: { q: query },
cancelToken: cancelToken.token
});
results.value = response.data;
} catch (error) {
if (!axios.isCancel(error)) {
console.error('Search failed', error);
}
}
}This code checks if an active request token exists and cancels it before creating a new one. If the request is canceled, Axios throws a special error that we safely ignore so the app does not break.
Things to Watch Out For
A common mistake is relying solely on lodash debounce, thinking it prevents multiple requests entirely. Debouncing only delays when the request is sent; if a user types fast enough or network latency spikes, overlapping requests can still happen.
Another trap is forgetting to catch the cancellation error, which will throw unhandled promise rejections in your browser console. Always check for cancellations using Axios helper methods.
Open your current project's search or autocomplete component today and add request cancellation to make your UI bulletproof.