AJAX on web page unloading


TL;DR On page unload AJAX network requests are sent by all browsers if – contrary to the general advice – the synchronous flavour of  XMLHttpRequest (SJAX) is used.

Update (4. November 2015):

  • Use the "pagehide" event instead of the "unload" event, since if an unload handler is present, the in-memory cache („Back-Forward-Cache“) is not enabled for the page.
  • Firefox and Google Chrome implement the Beacon API especially tailored for sending data during unloading of the document. But it has issues when quitting the browser.
  • Using SJAX comes with the penalty that the browser tab is blocked until the response from the remote server is received.

 The Problem of sending goodbye data on page unload

occurs often that a single page web application (SPA) needs to change the state in its cloud end (clean up resources, close network connections…) when a user quits the application (i.e. she closes the browser window).
The obvious choice is to subscribe for the DOM window’s pagehide, unload and/or beforeunload events with handler methods and trigger a remote signal on a server via XMLHttpRequest (i.e. AJAX). The result of that signalling is usually of no interest to the SPA front end (browser page).
However what can be done in these handlers has always depended on the various browser implementations.

The beforeunload Event Handler

can prompt the user to remain in the SPA showing a native UI dialog while JavaScript execution is halted. For creating network requests the same constraints as with the unload handler apply, except for the Chrome browser.

In the unload Event Handler

the UI is already gone. Therefore UI operations (alert, window.open,…) do not make sense here. How much JavaScript execution time remains is unknown. However to deduct that operations in here have to be fast and avoid all blocking JavaScript instructions all together is wrong!
Tests (see the table below) show that many browsers do not issue network requests if done asynchronously.

The Solution

is to use AJAX without the first ‚A‘ or S(ynchronous)JAX if there were such a thing. Thus simply setting the async flag of the XMLHttpRequest.open method to false ensures the network request is fired by all browsers. But never mind about that blockingness of the JavaScript instruction, because we are not interested in the response anyway!

The Beacon API did not succeed sending data while quitting the browser. Even more annoying is that navigator.sendBeacon returns true indicating that the request is scheduled. Thus it is not possible to employ a fallback method. For this case I’ve found SJAX to be more robust than the Beacon API.

Test Method

The network activity was detected by running Fiddler Web Debugger and analysing the logs on PutsReq.

Test Results

AJAX (async = true)okokfails?
AJAX (async = true)
after dismissed a beforeunload prompt
okfails sometimesfails?
SJAX (async = false)okokokok
„pagehide“ event handler
v.14v.11v.43v.47 / v.39 on Android 5.1v.9 / on iOS 10.2
page navigationsendBeaconAJAXAJAX, sendBeaconAJAX, sendBeaconSJAX / SJAX
page reloadsendBeaconAJAXAJAX, sendBeaconSJAX, sendBeaconSJAX / SJAX
closing the tabsendBeaconAJAXAJAX (FF 44) |
SJAX (FF 43), sendBeacon
sendBeaconSJAX / –
closing the browsersendBeaconAJAX– / n/a– / n/a