3

I need to make sure that when someone reloads or closes my page, their progress is saved. To save progress, I do a POST via XMLHttpRequest(), sending the data to server. I'm triggering this saveData() function inside a window.onbeforeunload event.

The problem is, that saveData() does some calculations, and then calls a sendData(content) to finally actually POST the data. And if the data I'm processing&sending is large (>100kB), the window seems to close before all the data gets through to the server. (I'm sending an image, and some times I only get half of it on the other side)

The http request is synchronous, xhr.open("POST", url, false), but that doesn't seem to cut it.

So my question is, how can I keep the onbeforeunload function from terminating, UNTIL xhr.readyState == 4? How do I make it wait for that event?

Oh, and setTimeout() will not work. The window will close before the "Time" comes.

This won't work:

if (!jQuery) {
    setTimeout(attachCode, 100);
    return;
} else {
    // continue and close
}

Thanks for any insight!

PS: this shouldn't be "bad practice" since it only takes a few of seconds and I don't want the user to have to save manually. Also, saving while he works (as in, before he closes window), would slow down the app so I can't do that.

[EDIT] As a temporary measure, I resorted to using this trick to auto save the data if the user decides to stay on the page. However, I'd really like to not need to use any alert messages. :(

Community
  • 1
  • 1
Spectraljump
  • 4,189
  • 10
  • 40
  • 55

2 Answers2

1

Disallowing the browser to do it's normal behaviour is normally a bad idea. And with onbeforeunload you can't pause the unload, you can only let the user know, that he/she is leaving the page and then let them decide, whether or not to leave the page - and thus the data unsaved.

So i your case, i would suggest an draft autosave, like you see in Google documents + a warning when the user leaves the page with unsaved data.

Tokimon
  • 4,072
  • 1
  • 20
  • 26
  • I agree. But I really hate it when sites stop the user with a popup and ask them to save. In my case, there's no way he wouldn't like to save, and it takes 3 seconds. It's turning out to be troublesome though... – Spectraljump Feb 25 '11 at 12:14
1

Actually you can slow down the browser before unloading. The problem lies in how JS handles the ajax requests.

Quite a while ago I had to do a quick and dirty hack about almost the same thing - logging some stuff, before navigating. The only way I found to do it is to wait for the return value of the XHR request.

Even though it's synchronous, the execution of the code forks in background and doesn't actually block the browser. You have to get the return value to be able to halt the script to upload the data.

Mind that I used jQuery for this, but it applies to native JS (I think.. :))

/* some code above */
var request = {
    async:false,
    cache: false,
    url: this.serviceURL,
    type: 'POST',
    data: {...},
    success: function(data) {}
};
try {
    var asd = $j.ajax(request); // do the request and wait
}
catch (e) {}
/* some code below */

I hope this helps.

bisko
  • 3,948
  • 1
  • 27
  • 29
  • Thanks for the try-catch trick. However, it seems that it works for refresh but not for close. This either means that the browser (chrome) force-closes the tab regardless of the script, either means that the refreshing takes longer and the script has time to finish -in which case it also means that I'm doing it wrong... The idea was to use `try{}catch(){}` to wait for the ajax function to return a value, right? – Spectraljump Feb 25 '11 at 12:12
  • [update] Basically, if I insert an `alert()` after `var asd = jQuery.ajax(request);`, it never gets triggered if I close the tab. It does work though for refresh. – Spectraljump Feb 25 '11 at 12:21