Re: [whatwg] Load events fired during onload handlers

2012-11-29 Thread Ian Hickson
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

2012-08-02 Thread Henri Sivonen
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

2012-07-31 Thread Boris Zbarsky

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

2012-07-30 Thread James Graham
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

2012-07-30 Thread Boris Zbarsky

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

2012-07-30 Thread James Graham

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