JavaScript

Ajax without jQuery

It took me a long time to implement jQuery into my everyday workflow but now I am so used to it that I rely on it entirely for some tasks. The more I use, the more I forget how to manually make stuff. How do you make an HTTP request without jQuery?

jQuery took all the complexity out of the equation. If I want to make a GET request, all I have to do is use the $.get() method. For post, just use $.post();

Browsers have come a long way, still on some rare cases, we have to support older browser. But writing code that works everywhere is not so hard anymore. So today, let's try to understand how Ajax works in vanilla JS.

Without jQuery, well there are a few things to be aware off before starting.

The XMLHttpRequest Object.

To make an ajax request we use the XMLHttpRequest object. You might be surprised to see the word XML in it. That's because when we started with those extra requests that didn't redirect the whole page business, the main data type returned was XML. It wasn't a requirement, but most developers where familiar with XML.

Today, we use the JSON data type mostly and newer browsers have native support for it. But before we worry about the returned data, let's see how to make the request.

IE didn't use XMLHttpRequest object in the old days, instead it relied on ActiveX. So we have to make sure to test before we create the object.

var isActiveX = !!window.ActiveXObject,
    xhr = isActiveX ? new ActiveXObject("Microsoft.XMLHTTP"): new XMLHttpRequest();

Now we have an active XMLHttpRequest object we can use to fetch data from our server. The method we need to set all our options is .open(). It takes 3 parameters:

xhr.open(method,url,async);

The first parameter is the method. You can use any valid HTTP methods such as GET, POST, PUT, DELETE. The second parameter is the url, you can use it to pass not only the url but the GET parameters as well. The third parameter is a boolean. true will make the request asynchronous, false will be synchronous.

After that, all you have to do is send the data to your server and the request is complete.

xhr.send();

If your set the request to be asynchronous, .send() returns as soon as you call it. For synchronous, it will block until the request is completed, meaning your code will be halted for a while.

So here is the complete code to make an Ajax request.

var isActiveX = !!window.ActiveXObject,
    xhr = isActiveX ? new ActiveXObject("Microsoft.XMLHTTP"): new XMLHttpRequest();

xhr.open("GET","/post-data",true);
xhr.send();

Very simple isn't it? Now if you want to add the extra features jQuery provides, you will have to write a little more code. We can make use of the event handlers that come with the xhr object to call different functions based on the result. onreadystatechange is called every time there is a status change on the request. Those changes are reflected on the .readyState property.

Here are the values:

0   Unsent
1   Opened
2   Headers received
3   Loading
4   Complete

When the request is complete, we can retrieve the response data and use it. If for example the data returned is JSON, we can parse it, and call it with our own function.

xhr.onreadystatechange = function () {
    if (this.readyState === 4 && this.status === 200){
        // the request is complete, parse data and call callback
        var response = JSON.parse(this.responseText);
        customFunction(response);
    }
};

Just like that we can recreate all the amazing functions available in jQuery, without having to load the entire library. We can wrap this code inside an Ajax object and make use of all these calls.

var Ajax = {
    xhr : null,
    request : function (url,method, data,success,failure){
        if (!this.xhr){
            this.xhr = window.ActiveX ? new ActiveXObject("Microsoft.XMLHTTP"): new XMLHttpRequest();
        }
        var self = this.xhr;

        self.onreadystatechange = function () {
            if (self.readyState === 4 && self.status === 200){
                // the request is complete, parse data and call callback
                var response = JSON.parse(self.responseText);
                success(response);
            }else if (self.readyState === 4) { // something went wrong but complete
                failure();
            }
        };
        this.xhr.open(method,url,true);
        if (method === "POST"){
            this.xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
            this.xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
            this.xhr.send(data);
        }else {
                this.xhr.send();
        }
    },
};

You can extend this to object to support everything you want and arm your own library. Feel free to share what you create with it.

Ajax.request("/hello-world/ajax","GET",null,function(data){
    console.log("Success");
},function(){
    console.log("failed");
},);

Comments(7)

tom :

Nice script, but how would it work with multiple concurrent requests? would the xhr object handle that, or do you need to create more than one instance?

Ibrahim :

Hi @Tom. Thank you for making that observation. You are right, this particular way I coded would only run one request at a time.

Instead you can create a new XMLHttpRequest() object for each request if you want it to run in parallel. Example:

var Ajax = {
    request : function (url,method, data,success,failure){
        // Here
        var xhr = window.ActiveX ? new ActiveXObject("Microsoft.XMLHTTP"): new XMLHttpRequest();
        xhr.onreadystatechange = function () {
            if (xhr.readyState === 4 && xhr.status === 200){
                // the request is complete, parse data and call callback
                var response = JSON.parse(xhr.responseText);
                success(response);
            }else if (xhr.readyState === 4) { // something went wrong but complete
                failure();
            }
        };
        xhr.open(method,url,true);
        xhr.send();
    }
};

Thank you for the insightful comment.

Jeromy :

The Ajax.request method accepts "data" but does nothing with it.

Ibrahim :

Hi Jeromy

I haven't added any functionality, but you can easily check if the method is of type POST then use the data in the xhr.send() to send post data.

Jeromy :

I know how to send data, I was just pointing it out. Thanks

Robert :

Hello Ibrahim thank you for this article

It would have been fantastic if you would have added two brief example of practical application, one with GET and one with POST e.g form submission or pagination

E.G. I have read that POST allows to manage the parameters (variables) sent as parameters

Ibrahim :

Hi Robert. Thank you for reading. This is a great idea. I'll update the post with examples as soon as possible.

Let's hear your thoughts

For my eyes only