Unload event never fires in IE
Spocke We recently found a serious bug in IE where the unload event wouldn’t fire on a specific page we had on a site. After some bug tracking we found out that the unload event never fired since all the contents of the page hadn’t finished loading before we navigated to another page.
This is a major problem since the unload event is commonly used to clear circular references etc in IE to prevent memory leaks. So this bug makes all Ajax libraries/frameworks out there that depend on the unload event on IE to fail if the page is unloaded before the contents of the page finished loading.
Here is an example of the bug, run the page in IE and follow the instructions on the page. Below is JS source code that is used on that page.
function unload() {
alert('Unload event occured.');
};
window.attachEvent('onunload', unload);
After some digging around we finally found a solution for the problem. The beforeunload event is fired correctly in IE but since this event can be blocked by setting the returnValue to an string value we couldn’t just add the memory cleanup logic there since the user might press cancel on the beforeunload event confirm dialog and then we would have removed all events on the page. So we needed to detect when the page was unloaded and we found out that the stop event can be used to detect this. It fires when the page is unloaded but unfortunately it also fires when the user pressed the stop button in the browser so we needed to add a fix for that as well.
Here is an example of the fixed version. You notice that this will fire the unload event correctly. Below is JS source code that is used on that page.
function fixUnload() {
// Is there things still loading, then fake the unload event
if (document.readyState == 'interactive') {
function stop() {
// Prevent memory leak
document.detachEvent('onstop', stop);
// Call unload handler
unload();
};
// Fire unload when the currently loading page is stopped
document.attachEvent('onstop', stop);
// Remove onstop listener after a while to prevent the unload function
// to execute if the user presses cancel in an onbeforeunload
// confirm dialog and then presses the stop button in the browser
window.setTimeout(function() {
document.detachEvent('onstop', stop);
}, 0);
}
};
function unload() {
alert('Unload event occured.');
};
window.attachEvent('onunload', unload);
window.attachEvent('onbeforeunload', fixUnload);
The only problem we still have is that if you hit F5 and force a refresh the unload event will still not fire. So if anyone has some good ideas on how to fix that it would be more than welcome.
Posted in Development
April 8th, 2008 at 16:15
Some clever bughunting! Are all IE versions affected (IE6 & IE7 & IE8b1), or is it a specific one?
April 8th, 2008 at 17:21
Okay, it’s really a hack, but it’s internet explorer…
Why do you don’t use a keycode to listen for the F5? Okay, it wouldn’t triggered if you hit the refresh button.
Greetings,
Martin
April 9th, 2008 at 00:29
@Bramus: It affects IE6 and IE7 haven’t tested IE8.
@Martin: Yes, it’s a real ugly hack. Yes, trapping F5 might work just fine I will fiddle somewhat with that.
April 14th, 2008 at 18:15
[...] table or add classes to it. This was also added to normalize the browser behavior. We also fixed a new type of memory leak in IE” – Announcement – Download – Changelog Spread the [...]
April 17th, 2008 at 17:52
[...] Sörlin found that sometimes his unload event never fired in IE: We recently found a serious bug in IE where the unload event wouldn’t fire on a specific page [...]
April 17th, 2008 at 19:10
I hardly see this one as a bug: since the onload event didn’t trigger in your example, I can understand why the unload do not as well.
So, if you use the onload to attach and onunload to detach your events, you’re not leaking.
But if you use a “DOMReady” technique, you’re in trouble if you use the onunload. You should use some kind of “DOMDisposed” technique then.
April 17th, 2008 at 19:41
This is a bug since the unload event should always fire if a document is unloaded. I don’t see how this has anything to do with DOMReady you tend to want to add events before all contents is loaded on the page DOMReady is normally fired before the onload event and that is the problem.
You must remove the event handles on unload in IE if you use closures or it will leak and the only way to do that is to use the unload or beforeunload events.
April 17th, 2008 at 22:52
[...] Sörlin found that sometimes his unload event never fired in IE: We recently found a serious bug in IE where the unload event wouldn’t fire on a specific page [...]
May 6th, 2008 at 08:23
A question for those smarter than me…
Wouldn’t the “onbeforeunload” cause a leak (aka the JS/DOM style leak), since it is never detached?
ie: shouldn’t the setTimout() also detach the “fixUnload”?
May 6th, 2008 at 09:29
The fixUnload doesn’t leak in the example since it’s not used inside a closure. But the stop function is so it needs to be properly detached.
This code is more of a proof of concept than a real usable code piece normally you would contain it in a library and then you need to fix it up a bit.
February 19th, 2009 at 09:51
this code works good for problem mentioned above , but my problem is to stop unloading of document on the event onbeforeunload.