Re: [whatwg] Load events fired during onload handlers
On Mon, 30 Jul 2012, James Graham wrote: There seems to be general agreement (amongst browsers, not yet the spec) that if a document does something that causes a new load event from within an onload handler (document.open/document.close) the second load event is not dispatched. This also applies to the load event on iframe elements if an event handler in the iframe would synchronously cause a second load event to fire. There is not agreement about what happens where there are multiple frames e.g. if a load event handler on iframe element A would cause a load event in iframe B, should the handler on B fire. Gecko says yes, WebKit no. There is a slightly rubbish demo at [1]. [1] http://software.hixie.ch/utilities/js/live-dom-viewer/saved/1686 On Tue, 31 Jul 2012, Boris Zbarsky wrote: Gecko fires the load event on the iframe as part of the default action of the load event on the window inside that iframe. I think the spec might actually call for it to fire async instead, though I haven't tested what other UAs do there. Per spec it's effectively async. More importantly, though, per spec the 'load' event on the iframe is delayed by some stuff that the 'load' event _in_ the iframe isn't delayed by, e.g. readyState changes, pageshow is fired, and delayed printing steps are executed, between them. The code for firing the load event looks somewhat like this: if (!mEODForCurrentDocument) { mIsExecutingOnLoadHandler = true; // Fire onload here mIsExecutingOnLoadHandler = false; mEODForCurrentDocument = true; } and the handling for document.open() sets mEODForCurrentDocument to false. Now what happens is we enter the above code for the normal load. We fire the onload handler, which does the open()/write()/close() thing. That tries to set mEODForCurrentDocument to false, but of course it's already false. When close() happens, onload does NOT fire sync from the close() call, because there are still outstanding async tasks on the new document that block onload. So we unwind the stack to the code above, and set mEODForCurrentDocument to true, and block any further firing of onload for this document until another open() call happens. Fundamentally, that looks like a bug in the handling of mEODForCurrentDocument, really. So if either that bug were fixed or item #1 above were changed, I think you'd get two load events here in Gecko right now. I haven't changed the spec to match Gecko here, since you seem open to changing Gecko. :-) On Mon, 30 Jul 2012, James Graham wrote: On 07/30/2012 05:44 PM, Boris Zbarsky wrote: On 7/30/12 11:10 AM, James Graham wrote: I don't think I have a strong opinion about what should happen here, but the Gecko behaviour could be easier to implement, and the WebKit behaviour slightly safer (presumably the point of this anomaly is to prevent infinite loops in load event handers). In Gecko's case, the only thing like that I know of is that onload fires synchronously in Gecko in some cases, I believe. So we had to put in some sort of recursion guard to prevent firing onload on a parent in the middle of a child firing onload or something like that. See https://bugzilla.mozilla.org/show_bug.cgi?id=330089. Per spec, onload is always async, so this wouldn't be a concern. Yeah, but as far as I can tell all browsers block (same document) load events that happen from inside onload [1], so I *guess* at some point in the past a site got into an infinite loop by trying to use document.open from inside onload. [1] https://www.w3.org/Bugs/Public/show_bug.cgi?id=17231 I wrote a similar test to the one you put in the bug: http://damowmow.com/playground/demos/onload/001.html It shows the onload handler actually getting called again in Gecko. The interesting thing about the test in the bug is that it's actually the iframe's onload that's not being called again, no page onload is being tested in that test. So for that test, the solution I suggested in comment 10 in that bug is worthless. Also interesting is that if you check what's actually going on, you'll find that in Opera and Gecko (and per spec) the iframe's onload is run asynchronously, whereas in WebKit it's synchronous. That it's asynchronous means that what we need to do is: * in the iframe code that fires 'load', annotate the iframe's document so that it knows we're in a 'load' event handler, * in the document.open() code, set a flag to true if the aforementioned annotation is set, and false otherwise, * in the iframe code that fires 'load', don't fire 'load' if the aforementioned flag is set. Sibling frames: http://software.hixie.ch/utilities/js/live-dom-viewer/saved/1937 http://software.hixie.ch/utilities/js/live-dom-viewer/saved/1938 Gecko and Opera go on to infinity there; WebKit blocks, but being synchronous means that the algorithm above would
Re: [whatwg] Load events fired during onload handlers
For what it's worth, I think the weirdness described in this thread is a good reason not to try to make DOMContentLoaded consistent with the load event for the sake of consistency. For one thing, the code that manages the weirdness of the load event lives in a different place compared to the code that fires DOMContentLoaded. -- Henri Sivonen hsivo...@iki.fi http://hsivonen.iki.fi/
Re: [whatwg] Load events fired during onload handlers
On 7/30/12 12:02 PM, James Graham wrote: If desired, I can try to figure out exactly why there's only one load event on the first iframe there. Let me know. That would be really helpful. OK, I looked into this. There are two things going on: 1) Gecko fires the load event on the iframe as part of the default action of the load event on the window inside that iframe. I think the spec might actually call for it to fire async instead, though I haven't tested what other UAs do there. 2) The code for firing the load event looks somewhat like this: if (!mEODForCurrentDocument) { mIsExecutingOnLoadHandler = true; // Fire onload here mIsExecutingOnLoadHandler = false; mEODForCurrentDocument = true; } and the handling for document.open() sets mEODForCurrentDocument to false. Now what happens is we enter the above code for the normal load. We fire the onload handler, which does the open()/write()/close() thing. That tries to set mEODForCurrentDocument to false, but of course it's already false. When close() happens, onload does NOT fire sync from the close() call, because there are still outstanding async tasks on the new document that block onload. So we unwind the stack to the code above, and set mEODForCurrentDocument to true, and block any further firing of onload for this document until another open() call happens. Fundamentally, that looks like a bug in the handling of mEODForCurrentDocument, really. So if either that bug were fixed or item #1 above were changed, I think you'd get two load events here in Gecko right now. -Boris
[whatwg] Load events fired during onload handlers
There seems to be general agreement (amongst browsers, not yet the spec) that if a document does something that causes a new load event from within an onload handler (document.open/document.close_ the second load event is not dispatched. This also applies to the load event on iframe elements if an event handler in the iframe would synchronously cause a second load event to fire. There is not agreement about what happens where there are multiple frames e.g. if a load event handler on iframe element A would cause a load event in iframe B, should the handler on B fire. Gecko says yes, WebKit no. There is a slightly rubbish demo at [1]. I don't think I have a strong opinion about what should happen here, but the Gecko behaviour could be easier to implement, and the WebKit behaviour slightly safer (presumably the point of this anomaly is to prevent infinite loops in load event handers). [1] http://software.hixie.ch/utilities/js/live-dom-viewer/saved/1686
Re: [whatwg] Load events fired during onload handlers
On 7/30/12 11:10 AM, James Graham wrote: I don't think I have a strong opinion about what should happen here, but the Gecko behaviour could be easier to implement, and the WebKit behaviour slightly safer (presumably the point of this anomaly is to prevent infinite loops in load event handers). In Gecko's case, the only thing like that I know of is that onload fires synchronously in Gecko in some cases, I believe. So we had to put in some sort of recursion guard to prevent firing onload on a parent in the middle of a child firing onload or something like that. See https://bugzilla.mozilla.org/show_bug.cgi?id=330089. Per spec, onload is always async, so this wouldn't be a concern. I'm not quite sure what causes the behavior you're seeing in Gecko at http://software.hixie.ch/utilities/js/live-dom-viewer/?saved=1686, but at first glance it's sort of accidental... Which doesn't mean we shouldn't spec it, of course; it just means that figuring out what to spec is harder. :( If desired, I can try to figure out exactly why there's only one load event on the first iframe there. Let me know. -Boris
Re: [whatwg] Load events fired during onload handlers
On 07/30/2012 05:44 PM, Boris Zbarsky wrote: On 7/30/12 11:10 AM, James Graham wrote: I don't think I have a strong opinion about what should happen here, but the Gecko behaviour could be easier to implement, and the WebKit behaviour slightly safer (presumably the point of this anomaly is to prevent infinite loops in load event handers). In Gecko's case, the only thing like that I know of is that onload fires synchronously in Gecko in some cases, I believe. So we had to put in some sort of recursion guard to prevent firing onload on a parent in the middle of a child firing onload or something like that. See https://bugzilla.mozilla.org/show_bug.cgi?id=330089. Per spec, onload is always async, so this wouldn't be a concern. Yeah, but as far as I can tell all browsers block (same document) load events that happen from inside onload [1], so I *guess* at some point in the past a site got into an infinite loop by trying to use document.open from inside onload. I'm not quite sure what causes the behavior you're seeing in Gecko at http://software.hixie.ch/utilities/js/live-dom-viewer/?saved=1686, but at first glance it's sort of accidental... Which doesn't mean we shouldn't spec it, of course; it just means that figuring out what to spec is harder. :( If desired, I can try to figure out exactly why there's only one load event on the first iframe there. Let me know. That would be really helpful. [1] https://www.w3.org/Bugs/Public/show_bug.cgi?id=17231