You are here

Failed to load Synchronous XHR in page dismissal

Submitted by Asif Nowaj, Last Modified on 2020-06-09

Overview:

Synchronous XHR i.e. ajax call during page dismissal (i.e. navigated away or closed by user) is being deprecated with M78 and onwards. Which means any ajax call from page unload events will be disallowed for Chrome. Below is the lists of page unload events are considered here:

1. beforeunload 2. unload 3. pagehide 4. visibilitychange

Reason:

Simply it hurts end user experience, when the user is trying to leave the page or navigate away (up to a max timeout of 1s, which is 2s in practice in chrome) but because of synch XHR call to save data or preventing data loss take max times to navigate away. So Chrome wants to improve end users experience.

There another reason to think of. There are too many ways available to go away from a Mobile browser or close a tab without firing page unload event, so unload events often don’t fire.

Alternatives:

1. Use Fetch keepalive

2. Use sendBeacon

3. Opt-out till Chrome 85 (~Oct, 2020)

Use Fetch keepalive:

When keepalive is true, it means the request may “live” even though the webpage who initiates is not “live”. So use keepalive true when using unload events, like below:


window.addEventListener('unload', {
  fetch('/siteAnalytics', {
    method: 'POST',
    body: getStatistics(),
    keepalive: true
  });
}

In general, all requests get aborted when a document is unloaded. But keepalive option tells the browser to perform the request in background, even after it leaves the page. So this option is essential for our request to succeed.

Limitations:

  • We can’t send megabytes: the body limit for keepalive requests is 64kb. So you need to send the data more regularly so that the amount of data in never bigger than 64kb.
  • Once this call is made there is no way to handle the server response. Any callback function won’t work as the page is already unloaded. So basically this kind of request, design an empty response from server.

Use sendBeacon:

The navigator.sendBeacon() method asynchronously sends a small amount of data over HTTP to a web server.

Syntax:


navigator.sendBeacon(url, data);
It sends data provided by the data parameter to the URL. url

The URL that will receive the data. Can be relative or absolute.

data

A ArrayBuffer, ArrayBufferView, Blob, DOMString, FormData, or URLSearchParams object containing the data to send.

Return values

The sendBeacon() method returns true if the user agent successfully queued the data for transfer. Otherwise, it returns false.

So below old code

window.addEventListener("unload", function logData() {
  var xhr = new XMLHttpRequest();
  xhr.open("POST", "/log", false); // third parameter of `false` means synchronous
  xhr.send(analyticsData); 
});
Would be replaced with simple

window.addEventListener("unload", function logData() {
  navigator.sendBeacon("/log", analyticsData);
});

With the sendBeacon() method, the data is transmitted asynchronously when the User Agent has an opportunity to do so, without delaying unload or the next navigation. This solves all of the problems with submission of analytics data:

The data is sent reliably

It's sent asynchronously

It doesn't impact the loading of the next page

In addition, the code is simpler to write than any of the older techniques!

The beacon sends an HTTP request via the POST method, with all relevant cookies available when called.

Opt out:

To help developers migrate away from using these APIs, this feature can still be turned back on:

Discussion or Comment

If you have anything in mind to share, please bring it in the discussion forum here.

https://forum.everyething.com/others-f41/