Why and how to abort an ajax call in jQuery.

Lets think about you have an input field and you attached an autocomplete function to that input field.

For an autocomplete functionality what we need to do is attaching a keyup event handler to that input field and every keyup call an ajax to get the desire results.

Lets think below is the input field
<input id=”search” name=”search” type=”text” >

And a div where we show the autocomplete list
<div id=”result”></div>

And the code for an autocomplete function is like

$(function(){
    $('#search').keyup(function() {
        var q = $(this).val();
        $.ajax({
            type: 'POST',
            data: 'q=' + q,
            url: 'AJAX_URL',
            success: function(response) {
                $('#result').html(response).show();
            }
        });
    });
});

Above code works great and you will have a nice autocomplete feature in place.

But did you think when you search by more than one character then what happen.

A new ajax request will be made for each and every character you entered. Lets take an example, you want to see an autocomplete list for “John”.

When you entered “J”, an ajax call will be made for “J”, then when you entered “o”, another call will be made for “Jo” and so on.

So to search “John”, you have 4 ajax calls for “J”, “Jo”, “Joh” and “John” and all 3 ajax response are useless to you except “John” one.

But you are thinking at the end of all ajax call user will get response of “John” and will see the correct response. And here you made the mistake. Remember ajax are asynchronous so it never happen sequentially.  You may call all ajax in a sequence but there are no guarantee that you will get the response in same sequential order.

Lets take the above example. You have 4 ajax calls in place. Though these are asynchronous calls, it may happen that you get response of ajax 4 before ajax 3 completes. So you were expecting results for “John” but you end up getting result of “Joh” which is weird to user.

Take another real life example. Suppose we are working on an e-commerce website where we list lots of product with different filter option.

Lets say we have selected t-shirts and in this page we have filter options for brands and all brands are associated with a checkbox to filter the list.

Here we made an ajax request when we click on a checkbox and filter the list.

Lets think i checked ‘Adidas’, ‘Nike’, ‘Reebok’ and ‘Puma’ and i will have 4 ajax call in place like

ajax 1: ‘Adidas’
ajax 2: ‘Adidas, Nike’
ajax 3: ‘Adidas, Nike, Reebok’
ajax 4: ‘Adidas, Nike, Reebok, Puma’

Though these are asynchronous call it may be possible you get ajax 1 response at the end. So what user will see? He will be seeing his all 4 filter options are checked but he is just seeing filter list by ‘Adidas’. Don’t you think, this is a very bad user experience?

So how we can solve this.

We will do one thing, before calling any ajax, we will check if there any pending ajax request for same ajax function. If there are any pending ajax call then we will cancel those and make a fresh/new ajax call.

jQuery provides a great function to cancel any ajax call any time called abort(). We will use this abort() function to cancel any pending ajax before calling the same.

We will take an variable which will store the status of any pending ajax call and default value will be set to null means no ajax call in place like

var progress = null;

This variable value will be updated when a ajax call is made like

progress = $.ajax();

We will set this variable value to null again when this ajax call completes like

complete: function(data) {
     progress = null;
 }

So progress has the latest ajax status. Before making any new ajax call we will check progress’s status and will see progress is null or not.

If progress isn’t null then we will abort the previous call then we will made the new call like.

beforeSend : function()    {
     if(progress != null) {
         progress.abort();
     }
 }

And the complete function will be like

$(function(){
    var progress = null;
    $('#search').keyup(function() {
        var q = $(this).val();
        progress = $.ajax({
            type: 'POST',
            data: 'q=' + q,
            url: 'AJAX_URL',
            beforeSend : function() {
                //checking progress status and aborting pending request if any
                if(progress != null) {
                    progress.abort();
                }
            },
            success: function(response) {
                $('#result').html(response).show();
            },
            complete: function(){
                // after ajax xomplets progress set to null
                progress = null;
            }
        });
    });
});