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
Some clever bughunting! Are all IE versions affected (IE6 & IE7 & IE8b1), or is it a specific one?
April 8th, 2008 at 16:15Okay, 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,
April 8th, 2008 at 17:21Martin
@Bramus: It affects IE6 and IE7 haven’t tested IE8.
April 9th, 2008 at 00:29@Martin: Yes, it’s a real ugly hack. Yes, trapping F5 might work just fine I will fiddle somewhat with that.
[...] 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 14th, 2008 at 18:15[...] 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 17:52I 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.
April 17th, 2008 at 19:10So, 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.
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 19:41[...] 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 22:52A 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 08:23The 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.
May 6th, 2008 at 09:29this code works good for problem mentioned above , but my problem is to stop unloading of document on the event onbeforeunload.
February 19th, 2009 at 09:51I have been after the Internet for this info and just wanted to say thanks to you for this post. BTW, just off topic, where can i get a version of this theme? – 10x
December 12th, 2010 at 20:40The theme is made by Arcin. Check the footer and the bottom right corner.
December 12th, 2010 at 23:24