74

I'm trying to do this:

$(window).unload( function () { 

$.ajax({
    type: "POST",
    url: "http://localhost:8888/test.php?",
    data: "test",
    success: function(msg){
         alert( "Data Saved: " + msg );
    }
}); 
alert (c);
});

However, the success alert is never shown, nor does this request seem to be even hitting the server. What am I doing wrong?

tshepang
  • 12,111
  • 21
  • 91
  • 136
Rob
  • 741
  • 1
  • 5
  • 3

7 Answers7

83

I believe you need to make the request synchronous instead (it's asynchronous by default) using the async : false parameter.

Synchronous requests lock up the browser until they complete. If the request is asynchronous, the page just keeps on unloading. It's quick enough that the request never even has time to fire off.

Roshana Pitigala
  • 8,437
  • 8
  • 49
  • 80
Nate B
  • 6,338
  • 25
  • 23
  • Thanks. Do you have explanation why this one must be synchronous? – zigomir Jan 07 '12 at 14:00
  • 2
    Synchronous requests lock up the browser until they complete. If the request is asynchronous, the page just keeps on unloading. It's quick enough that the request never even has time to fire off. – Nate B Jan 07 '12 at 17:31
  • Does this mean there's a chance, that if the browser takes extra long to unload (maybe harddrive issues) that the request could sometimes be sent? Or is it never sent. Just curious. – Farzher Jan 18 '13 at 18:08
  • 11
    While this is the correct answer, it upsets me that you haven't also noted that it's ***evil***. On slow network connections, you will stall users' browsers doing things this way. – Mark Amery Jul 05 '13 at 09:31
  • Did not make a difference – user3953989 Apr 14 '16 at 19:27
  • _"It's quick enough that the request never even has time to fire off"_, in some cases it actually fires the event, but doesn't wait for a response causing the connection to be closed. – Juan Carlos Mendoza Oct 15 '19 at 07:02
22

Try calling it with async = false;

jQuery.ajax({url:"http://localhost:8888/test.php?", async:false})

I just tried it.

Orson
  • 14,981
  • 11
  • 56
  • 70
18

The best solution is to use navigator.sendBeacon. It is brand new functionality which is starting to get implemented in new releases of browsers. The function is available in browsers newer than Chrome 39 and Firefox 31. It is not supported by Internet Explorer and Safari at the time of writing. To make sure your request gets send in the browsers that don't support the new functionality yet, you can use this solution:

var navigator.sendBeacon = navigator.sendBeacon || function (url, data) {
  var client = new XMLHttpRequest();
  client.open("POST", url, false); // third parameter indicates sync xhr
  client.setRequestHeader("Content-Type", "text/plain;charset=UTF-8");
  client.send(data);
};

This function does not allow you to register a onsuccess callback though.

lswartsenburg
  • 373
  • 3
  • 8
  • 1
    Currently, this is still listed as experimental and "syntax and behavior ... is subject to change in future versions" – Jeff Walker Code Ranger Aug 18 '15 at 15:04
  • UPDATE: This may not have been well known when you wrote this answer, but sendBeacon **should not** be used with the `unload` and `beforeunload` events, as it may not reliably fire—the `visibilitychange` event should be used instead. See the MDN docs for more information. – Henry Floyd Oct 20 '20 at 15:53
3

The HTML 5 Specification states that alert(), prompt(), etc. will not be available during the window.unload() event. Please see window.unload() for more details. You can check the result by using console.log('success'); instead of alert().

John Yeary
  • 1,112
  • 22
  • 45
2

Maybe you'd have more success using the onbeforeunload event instead?

   $(window).bind('beforeunload', ...
Scott Evernden
  • 39,136
  • 15
  • 78
  • 84
0

Your function and Ajax call look fine, so my guess is that your browser window is closed before ajax call has time to go to the server and back. The ajax call might return something when the window is closing, try adding error function to your ajax call to see if that's the case:

error: function (xhr, textStatus) {
    alert('Server error: '+ textStatus);
}
Marek Karbarz
  • 28,956
  • 6
  • 53
  • 73
  • 1
    I don't really need it to come "back" (i.e. that alert of success is not necessary, just used for debugging purposes). However, I do need the ajax request to be fired before the unload finishes. – Rob Nov 30 '09 at 18:49
0

MDN recommends using navigator.sendBeacon on the visibilitychange event.

$(window).on("visibilitychange", (event) => {
    if (document.visibilityState === 'hidden') {
        navigator.sendBeacon("https://example.com/endpoint", yourDataToSend);
    }
});

(Non-jquery version would use window.addEventListener("visibilitychange").)

From MDN:

Web sites often want to send analytics or diagnostics to the server when the user has finished with the page. The most reliable way to do this is to send the data on the visibilitychange event

Using unload and beforeunload events should be avoided.

This SO post appears to have good research about this situation as well.

Elijah Mock
  • 587
  • 8
  • 21