The original address: www.sitepoint.com/xmlhttprequ…

directory

  • From AJAX to AJAX
  • XMLHttpRequest
  • Fetch
    • Browser support
    • The default without cookies
    • Mistakes are not rejected
    • Timeout is not supported
    • Suspend the Fetch
    • There is no Progress
  • XMLHttpRequest vs Fetch?

2019 marks the 20th anniversary of Ajax. Arguably, the first implementation of XMLHttpRequest was released in 1999 as an IE5.0 ActiveX component.

Previously, there were ways to get data from the server without refreshing the page, but they often relied on clunky techniques such as

XMLHttpRequest didn’t become a Web standard until 2006, but was implemented in most browsers by then. Due to its adoption in Gmail and Google Maps, Jesse James Garrett published AJAX: A New Approach to Web Applications in 2005. The new term caught the attention of developers.

From AJAX to AJAX

AJAX is short for Asynchronous JavaScript and XML. Asynchronous” is obvious, but:

  1. While VBScript and Flash can also be implemented, JavaScript is more appropriate
  2. The payload did not have to be XML, although it was popular at the time. Today, you can use any data format, and JSON is usually the preferred format.

For now, we use “Ajax” as a generic term for clients fetching data from the server and dynamically updating the DOM without refreshing the entire page. Ajax is the core technology for most Web applications and single-page applications (spAs).

XMLHttpRequest

The following JavaScript code shows how to use XMLHttpRequest(often referred to simply as XHR) to make an HTTP GET request to http://domain/service.

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();
Copy the code

The XMLHttpRequest object has many properties, methods, and events. For example, you can set and monitor timeouts in milliseconds:

// set timeout
xhr.timeout = 3000; // 3 seconds
xhr.ontimeout = (a)= > console.log('timeout', xhr.responseURL);
Copy the code

And the Progress event can report long-running file uploads:

// upload progress
xhr.upload.onprogress = p= > {
  console.log( Math.round((p.loaded / p.total) * 100) + The '%'); }Copy the code

The number of attributes can be confusing, and early implementations of XMLHttpRequest were inconsistent across browsers. Therefore, many libraries and frameworks provide Ajax wrapper functions, such as the jquery.ajax () method:

// jQuery Ajax
$.ajax('http://domain/service')
  .done(data= > console.log(data))
  .fail((xhr, status) = > console.log('error:', status));
Copy the code

Fetch

The Fetch API is a modern alternative to XMLHttpRequest. Generic Header, Request, and Response interfaces provide consistency, while Promises allow simpler chained calls and async/await without callbacks.

fetch(
    'http://domain/service',
    { method: 'GET' }
  )
  .then( response= > response.json() )
  .then( json= > console.log(json) )
  .catch( error= > console.error('error:', error) );
Copy the code

Fetch is simple, elegant, and easy to understand, and is widely used in PWA Service workers. Why not replace the old XMLHttpRequest with it?

Unfortunately, Web development has never been so clear-cut. Fetch is not a perfect substitute for Ajax…

Browser support

The Fetch API is well supported in most browsers, but not all versions of IE. People using pre-2017 versions of Chrome, Firefox and Safari may also experience problems. These users may be a small percentage of your user base… It could also be a major customer. So before coding, be sure to confirm compatibility!

In addition, the Fetch API is newer and receives more ongoing updates than mature XHR objects. These updates are unlikely to break the original code, but some maintenance work is expected over the next few years.

The default without cookies

Unlike XMLHttpRequest, Fetch does not send cookies by default, so the authentication of the application may fail. You can solve this problem by changing the initial value passed in the second argument, for example:

fetch(
  'http://domain/service',
  {
    method: 'GET'.credentials: 'same-origin'})Copy the code

Mistakes are not rejected

Surprisingly, HTTP errors such as 404 Page Not Found or 500 Internal Server Error do Not cause the Fetch to return a Promise marked REJECT; .catch() is also not executed. To accurately determine whether the fetch is successful, it needs to include the promise resolved situation, and then determine whether response.ok is true. As follows:

fetch(
    'http://domain/service', 
    { method: 'GET' }
  )
  .then( response= > {
    if(response.ok) {
      return response.json();
    }
    throw new Error('Network response was not ok.');
  })
  .then( json= > console.log(json) )
  .catch( error= > console.error('error:', error) );
Copy the code

Reject is triggered only when a request cannot be completed, such as a network failure or a request being blocked. This complicates error catching.

Timeout is not supported

Fetch does not support timeout and the request will continue as long as the browser allows it. The solution is to wrap the Fetch in a Promise, for example:

// 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); }}Copy the code

Or use promise.race () to determine when the fetch or timeout completes first, for example:

Promise.race([
  fetch('http://url', { method: 'GET' }),
  new Promise(resolve= > setTimeout(resolve, 3000))
])
  .then(response= > console.log(response))
Copy the code

Suspend the Fetch

It is easy to terminate an XHR request with xhr.abort(), and it is also possible to monitor event resolution with the xhr.onabort function.

It was previously impossible to abort a Fetch request, but browsers that implement the AbortController API now support it. This will trigger a signal that can be passed to the Fetch start 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) );
Copy the code

Fetch can be aborted by calling Controller.abort (). When a Promise is marked reject, the.catch() function is called.

There is no Progress

As of this writing, Fetch still does not support progress events. Therefore, it is impossible to show the progress status of file uploads or large form submissions.

XMLHttpRequest vs Fetch?

In the end, the choice is yours… Unless your application is an IE client that requires an upload progress bar. You can also choose to use Fetch Polyfill in combination with Promise Polyfill to execute the Fetch code in IE.

For simpler Ajax calls, XMLHttpRequest is low-level, more complex, and you need to encapsulate functions. Unfortunately, the same goes for Fetch once you start to consider the complexities of timeouts, aborting calls, and error catching.

The future of Fetch is predictable. However, the API is relatively new, it does not provide all the functionality of XHR, and some parameter Settings are cumbersome. Therefore, in the future use process, please pay attention to the above problems.