XMLHttpRequest vs the Fetch API: What’s Best for Ajax in 2019?

Share this article

XMLHttpRequest vs the Fetch API: What’s Best for Ajax in 2019?
Weighing up whether to use XMLHttpRequest vs Fetch and its modern take on Ajax? We compare the pros and cons of both options.
March 2019 celebrates the 20th anniversary of Ajax. Sort of. The first implementation of XMLHttpRequest shipped in 1999 as an IE5.0 ActiveX component (don’t ask). Before then, there had been ways to pull data from a server without a full-page refresh, but they often relied on clunky techniques such as <script> injection or third-party plugins. Microsoft developed XMLHttpRequest primary for a browser-based alternative to their Outlook email client. XMLHttpRequest was not a web standard until 2006, but it was implemented in most browsers. Its adoption in Gmail (2004) and Google Maps (2005) led to Jesse James Garrett’s 2005 article AJAX: A New Approach to Web Applications. The new term crystallised developer focus.

AJAX to Ajax

AJAX is a mnemonic for Asynchronous JavaScript and XML. “Asynchronous” definitely, but:
  1. JavaScript was likely, although VBScript and Flash were options
  2. The payload did not need to be XML, although that was popular at the time. Any data format could be used and, today, JSON is normally preferred.
We now use “Ajax” as a generic term for any client-side process which fetches data from a server and updates the DOM dynamically without a full-page refresh. Ajax is a core technique for most web applications and Single-Page Apps (SPAs).

Extreme XMLHttpRequest

The following JavaScript code shows a basic HTTP GET request for http://domain/service using XMLHttpRequest (commonly shortened to XHR):
let xhr = new XMLHttpRequest();
xhr.open('GET', 'http://domain/service');

// request state change event
xhr.onreadystatechange = function() {

  // request completed?
  if (xhr.readyState !== 4) return;

  if (xhr.status === 200) {
    // request successful - show response
    console.log(xhr.responseText);
  }
  else {
    // request error
    console.log('HTTP error', xhr.status, xhr.statusText);
  }
};

// start request
xhr.send();
The XMLHttpRequest object has many other options, events, and response properties. For example, a timeout in milliseconds can be set and detected:
// set timeout
xhr.timeout = 3000; // 3 seconds
xhr.ontimeout = () => console.log('timeout', xhr.responseURL);
and a progress event can report on long-running file uploads:
// upload progress
xhr.upload.onprogress = p => {
  console.log( Math.round((p.loaded / p.total) * 100) + '%') ;
}
The number of options can be bewildering and early implementations of XMLHttpRequest had a few cross-browser inconsistencies. For this reason, most libraries and frameworks offer Ajax wrapper functions to handle the complexity, e.g. the jQuery.ajax() method:
// jQuery Ajax
$.ajax('http://domain/service')
  .done(data => console.log(data))
  .fail((xhr, status) => console.log('error:', status));

Fast Forward to Fetch

The Fetch API is a modern alternative to XMLHttpRequest. The generic Headers, Request, and Response interfaces provide consistency while Promises permit easier chaining and async/await without callbacks. The XHR example above can be converted to far simpler Fetch-based code which even parses the returned JSON:
fetch(
    'http://domain/service',
    { method: 'GET' }
  )
  .then( response => response.json() )
  .then( json => console.log(json) )
  .catch( error => console.error('error:', error) );
Fetch is clean, elegant, simpler to understand, and heavily used in PWA Service Workers. Why wouldn’t you use it instead of the ancient XMLHttpRequest? Unfortunately, web development is never that clear-cut. Fetch is not a full drop-in replacement for Ajax techniques yet…

Browser Support

The Fetch API is reasonably well-supported, but it will fail in all editions of Internet Explorer. People using releases of Chrome, Firefox and Safari older than 2017 may also experience problems. Those users may form a tiny proportion of your user base … or it could be a major client. Always check before you start coding! In addition, the Fetch API is newer and receives more ongoing changes than the mature XHR object. Those updates are unlikely to break code, but expect some maintenance work over the coming years.

Cookieless by Default

Unlike XMLHttpRequest, not all implementations of Fetch will send cookies so your application’s authentication could fail. The problem can be fixed by changing the initiation options passed in the second argument, e.g.
fetch(
    'http://domain/service',
    {
      method: 'GET',
      credentials: 'same-origin'
    }
  )

Errors Are Not Rejected

Surprisingly, an HTTP error such as a 404 Page Not Found or 500 Internal Server Error does not cause the Fetch Promise to reject; the .catch() is never run. It will normally resolve with the response.ok
status set to false. Rejection only occurs if a request cannot be completed, e.g. a network failure. This can make error trapping more complicated to implement.

Timeouts Are Not Supported

Fetch does not support timeouts and the request will continue for as long as the browser chooses. Further code is required to either wrap the Fetch in another Promise, e.g.
// fetch with a timeout
function fetchTimeout(url, init, timeout = 3000) {
  return new Promise((resolve, reject) => {
    fetch(url, init)
      .then(resolve)
      .catch(reject);
    setTimeout(reject, timeout);
  }
}
… or perhaps use Promise.race() to which resolves when either a fetch or a timeout completes first, e.g.
Promise.race([
  fetch('http://url', { method: 'GET' }),
  new Promise(resolve => setTimeout(resolve, 3000))
])
  .then(response => console.log(response))

Aborting a Fetch

It is easy to end an XHR request with xhr.abort() and, if necessary, detect such an event with an xhr.onabort function. Aborting a Fetch was not possible for several years but it is now supported in browsers which implement the AbortController API. This triggers a signal which can be passed to the Fetch initiation object:
const controller = new AbortController();

fetch(
  'http://domain/service',
  {
    method: 'GET'
    signal: controller.signal
  })
  .then( response => response.json() )
  .then( json => console.log(json) )
  .catch( error => console.error('Error:', error) );
Fetch can be aborted by calling controller.abort();. The Promise rejects so the .catch() function is called.

No Progress

At the time of writing, Fetch has no support for progress events. It is therefore impossible to report the status of file uploads or similar large form submissions.

XMLHttpRequest vs the Fetch API?

Ultimately, the choice is yours … unless your application has IE clients who demand upload progress bars. For simpler Ajax calls, XMLHttpRequest is lower-level, more complicated, and you will require wrapper functions. Unfortunately, so will Fetch once you start to consider the complexities of timeouts, call aborts, and error trapping. You could opt for a Fetch polyfill in conjunction with a Promise polyfill so it’s possible to write Fetch code in IE. However, XHR is used as the fallback; not every option will work as expected, e.g. cookies will be sent regardless of settings. Fetch is the future. However, the API is relatively new, it does not provide all XHR functionality, and some options are cumbersome. Use it with caution for the next few years.

Frequently Asked Questions (FAQs) about XMLHttpRequest and Fetch API

What are the main differences between XMLHttpRequest and Fetch API?

XMLHttpRequest and Fetch API are both used to make HTTP requests in JavaScript. However, they differ in several ways. Fetch API is a newer technology and is considered more powerful and flexible. It returns a Promise that resolves to the Response to that request, whether it is successful or not. Fetch also provides a generic definition of Request and Response objects. On the other hand, XMLHttpRequest is a bit older and does not use Promises, which can make the code more complex and harder to maintain. It does not have a generic definition of Request and Response objects.

Is Fetch API better than XMLHttpRequest?

Fetch API is generally considered to be a better choice for making HTTP requests in JavaScript due to its use of Promises. Promises make the code cleaner and easier to read, and they also make it easier to handle errors. Fetch API also has a more powerful and flexible feature set than XMLHttpRequest. However, XMLHttpRequest is still widely used and supported, and it may be a better choice in certain situations, such as when you need to support older browsers that do not support Fetch API.

Can Fetch API replace XMLHttpRequest?

Yes, Fetch API can replace XMLHttpRequest for making HTTP requests in JavaScript. Fetch API is a newer technology and has a more powerful and flexible feature set. It uses Promises, which makes the code cleaner and easier to read, and it also makes it easier to handle errors. However, XMLHttpRequest is still widely used and supported, and it may be a better choice in certain situations, such as when you need to support older browsers that do not support Fetch API.

What are the advantages of using Fetch API?

Fetch API has several advantages over XMLHttpRequest. It uses Promises, which makes the code cleaner and easier to read, and it also makes it easier to handle errors. Fetch API also has a more powerful and flexible feature set, including a generic definition of Request and Response objects. It also allows you to make requests to other origins, which is not possible with XMLHttpRequest.

What are the disadvantages of using Fetch API?

One of the main disadvantages of using Fetch API is that it is not supported by all browsers. Older browsers, in particular, may not support Fetch API. In these cases, you may need to use XMLHttpRequest or a polyfill. Another disadvantage is that Fetch API does not send cookies by default, so you need to manually set the credentials option to ‘include’ if you want to send cookies.

What are the advantages of using XMLHttpRequest?

XMLHttpRequest is a tried and tested technology for making HTTP requests in JavaScript. It is widely supported and can be used in all browsers. XMLHttpRequest also sends cookies by default, unlike Fetch API. This can be an advantage in certain situations, such as when you are making requests to a server that requires cookies for authentication.

What are the disadvantages of using XMLHttpRequest?

XMLHttpRequest does not use Promises, which can make the code more complex and harder to maintain. It also does not have a generic definition of Request and Response objects, and it does not allow you to make requests to other origins. XMLHttpRequest is also considered to be a bit outdated compared to newer technologies like Fetch API.

How do I choose between XMLHttpRequest and Fetch API?

The choice between XMLHttpRequest and Fetch API depends on your specific needs and the browsers you need to support. If you need to support older browsers that do not support Fetch API, then XMLHttpRequest may be a better choice. However, if you are working with newer browsers and you want to take advantage of the cleaner, more modern syntax and the more powerful and flexible feature set of Fetch API, then Fetch API would be the better choice.

Can I use both XMLHttpRequest and Fetch API in the same project?

Yes, you can use both XMLHttpRequest and Fetch API in the same project. You might choose to use XMLHttpRequest for certain tasks and Fetch API for others, depending on your specific needs and the browsers you need to support. However, it is generally recommended to stick with one or the other for consistency and ease of maintenance.

Are there any alternatives to XMLHttpRequest and Fetch API for making HTTP requests in JavaScript?

Yes, there are several alternatives to XMLHttpRequest and Fetch API for making HTTP requests in JavaScript. These include libraries like Axios, jQuery’s $.ajax, and SuperAgent. These libraries provide a higher-level interface for making HTTP requests and can offer additional features and conveniences compared to XMLHttpRequest and Fetch API.

Craig BucklerCraig Buckler
View Author

Craig is a freelance UK web consultant who built his first page for IE2.0 in 1995. Since that time he's been advocating standards, accessibility, and best-practice HTML5 techniques. He's created enterprise specifications, websites and online applications for companies and organisations including the UK Parliament, the European Parliament, the Department of Energy & Climate Change, Microsoft, and more. He's written more than 1,000 articles for SitePoint and you can find him @craigbuckler.

ajaxFetch APIjoelfXMLHttpRequest
Share this article
Read Next
Get the freshest news and resources for developers, designers and digital creators in your inbox each week