[whatwg] Should events be paused on detached iframes?

On Tue, 24 Aug 2010, Ben Lerner wrote:
>
> There seems to be a bit of disagreement among browsers about how event 
> loops and iframes interact when an iframe is removed and then reinserted 
> into its parent document.  Consider the following two documents: the 
> parent document has a button that removes or reattaches an iframe to the 
> document, while the second simply sets an interval to update the page 
> content.
> 
> Page1.html:
> <p><button onclick="toggleInDoc();">Show/hide</button></p>
> <iframe id="test" src="page2.html"></iframe>
> <script>
>     var test = document.getElementById("test");
>     function toggleInDoc() {
>       if (test.parentNode == null)
>         document.body.appendChild(test);
>       else
>         document.body.removeChild(test);
>     }
> </script>
> 
> Page2.html:
> <p id="test"></p>
> <script>
>     window.setInterval(function() { document.getElementById("test").innerHTML
> += "."; }, 500);
> </script>
> 
> Assume the user waits until the interval has fired several times, then 
> presses the button, waits a while, and presses it again.  There are 
> three possible outcomes:
>
> 1. When the iframe is reattached, the inner page reloads.  This seems to 
> go beyond the wording of the spec, which says only "When an iframe 
> element is first inserted into a document, the user agent must create a 
> nested browsing context, and then process the iframe attributes for the 
> first time."  (This isn't the first time the iframe is inserted into the 
> document, so we shouldn't process the iframe attributes again.)

Agreed that this contradicts the spec currently.


> 2. The interval (and presumably, all events) in the iframe is paused 
> while it's been detached (since the document is no longer fully active, 
> but it also has not been discarded because of the global reference to 
> its container element).

The timeout is paused. Events in general aren't necessarily paused; for 
example you can synchronously dispatch an event using dispatchEvent() on a 
document in an inactive browsing context. Tasks are paused though (so most 
events don't fire).

Actually, the spec wasn't really clear about the status of the browsing 
context of an iframe that was taken out of a document. I've made the spec 
clearer on this matter.


> 3. The interval (and presumably, all events) continues to fire while 
> it's been detached, and the content of page2 will have changed while 
> it's been detached from page1.

That doesn't match the spec.


> So far, Chrome 6, Opera 10.6 and Firefox 3.6 follow #1, and IE 8 follows 
> #3. My reading of the "fully active" clause of the spec leads me to 
> expect #2. Which of these behaviors is the desired one?  And/or, would 
> it be desirable to permit authors to specify which behavior they intend?

The spec is #2; it is an attempt to get as close to most existing browsers 
as is probably necessary for compatibility, while still allowing the 
iframe to be useful (e.g. for the regrafted-iframe trick used by GMail).


On Tue, 24 Aug 2010, Dmitry Titov wrote:
> 
> So it seems the right behavior is to keep the content alive. It's not 
> clear why the events would not fire during DOM operations though. 
> Perhaps they should, since nothing is changing from the perspective of 
> the document loaded into iframe - for example, XHR probably should 
> continue loading content if it was doing so before iframe was 
> disconnected from its parent node. Doing some suspension (as for example 
> is done when a page goes into back-forward cache?) would be way more 
> complex mechanism to have, with necessary events on pause/unpause so the 
> live document could re-start async operations correctly.

All that currently happens with respect to pausing is that tasks for the 
document don't get processed (they remain in the queue). It's actually the 
same mechanism that's used for back-forward interactions; per spec, 
currently, if you grab a reference (from another Window) to a document 
that you then send into session history (bfcache), you can still mutate 
that document, call dispatchEvent() on it, run scripts in it, etc. Since 
you have a reference to it, it won't get automatically evicted, and when 
you traverse the history back to it the changes will be visible (and 
queued events and other tasks, e.g. parsing, will start firing again).

The one difference between session history and moving an iframe out of a 
document is that with the session history when you send a document into 
the "back" history, it gets unload/pagehide events (and pageshow when it 
comes back), whereas the iframe doesn't get any notification at all.


On Tue, 24 Aug 2010, Dirk Pranke wrote:
>
> On a related note, the behavior of onUnload in this situation is quite 
> unclear. Should onUnload() fire if an iframe is detached from the DOM?

Not per spec.


On Tue, 24 Aug 2010, Dmitry Titov wrote:
>
> At least spec tells that if an iframe is detached from the DOM and then 
> becomes eligible for GC (not hold via JS reference not DOM connection) - 
> it gets unloaded w/o onunload firing (4.8.2)

Right. This is intended to avoid exposing the specifics of GC.


On Tue, 24 Aug 2010, Ben Lerner wrote:
>
> The history navigation analogy is a good one: pages presumably already 
> have to handle the pageshow event to deal with being revived from the 
> history, and the browser already needs to know how to fire that event.  

Pages don't _have_ to handle it; there's a number of cases, e.g. if they 
have any 'unload' event handlers, that result in a document being 
classified a lost cause. Search for "salvageable" in the spec.


> Why not reuse those mechanisms?  A strawman claim: Nothing may be 
> changing from the perspective of the iframe, but it certainly is 
> changing from the perspective of the container or the user: detaching an 
> iframe from a page is like navigating a browsing context away from a 
> page, putting it into hibernation until it's reattached to an active 
> document/browsing context.  What subtle or important facet of the web am 
> I missing that breaks this analogy? (It wouldn't surprise me if I missed 
> something obvious, either... :)

It's very rare, and done only by the author intentionally, so I'm not sure 
there's any reason to really provide a lot of infrastructure to support 
it. Just having the behaviour be whatever falls out of the way more 
important things are specced seems simpler and sufficient.


> Another reason to consider suspending detached iframes: suppose that in 
> the chat window example below, the iframe wasn't just a same-origin 
> place to store global state, but also had its own UI, with callbacks and 
> event handlers and whatnot.  If, during the interim while the iframe was 
> being detached, adopted and reattached, that frame executed a timer that 
> popped up a modal alert or prompt to the user, how would the user 
> reasonably know where that alert came from?  And what document(s?) 
> should be paused while the alert is shown?

Per spec, it can't get a timer or any callback or asynchronous event or 
network task while it is detached, so nothing could trigger the alert.


> Regarding XHR and such -- I guess what I'm suggesting is suspending the 
> event loop, but not necessarily suspending asynch processes.  So XHR can 
> continue to queue tasks; media can continue to buffer; resources can 
> continue to load.

That's what the spec currently requires (though the browser is of course 
entirely entitled to throttle any network traffic, etc).


On Tue, 24 Aug 2010, Boris Zbarsky wrote:
> 
> At least in the case of Gecko, there are at least the following things to keep
> in mind:
> 
> 1) "hibernating" documents are very limited in what one can do with
>    them (e.g. attempting to mutate the document in any way while
>    hibernating will throw it away).

On Wed, 25 Aug 2010, Boris Zbarsky wrote:
> 
> "throw away" in this context means throw away from the back/forward 
> cache. The document is still there, and can still be mutated, etc, but 
> can no longer become live again.

Ah, interesting. Ok. That doesn't really affect the iframe case, since in 
the iframe case the document doesn't stop being the active doc of its 
browsing context, it just stops being fully active (since it stops 
having a parent browsing context).


On Tue, 24 Aug 2010, Boris Zbarsky wrote:
> 
> 2) Documents have security policies applied to them based on the
>    toplevel content window (or browser tab, if you prefer to think
>    about it) they're associated with.  Which means that allowing
>    documents not immediately associated with any toplevel window,
>    which would be the case right now in Gecko for an <iframe> not in
>    a document, leads to security problems.  This could be changed by
>    redoing how the association is implemented, but there's some
>    touchy code involved that we'd rather not get wrong.  ;)

It's not clear to me what permissions would be based on the top-level 
browsing context rather than on the Window itself.


> Note that in Gecko documents with active network requests never go into 
> hibernation right now, precisely because we don't want to have to buffer 
> potentially-arbitrary amounts of data (see JPEG push) for arbitrary 
> lengths of time.  We still wouldn't want to do so in this case...

Currently the spec doesn't use "has pending network activity" as a flag to 
make a document non-salvageable, but allows documents to which nobody has 
a reference (excluding the reference from the session history) to be 
discarded arbitrarily, which is intended to handle this case (it's 
presumed that if you have a reference to a document then you want it to 
survive and will be using any buffering data).

I guess we could also allow browsers to even discard things in the session 
history that do have references to them, but long-term it might be better 
just to have the browsers support that, since it doesn't seem 
intrinsically impossible to do -- it's just something that is typically in 
a hairy part of code, because it's never been specced before. There's 
bound to be other things that need changing as we move all the browsers to 
a convergence point in this area, regardless of what we make the spec say.


On Thu, 26 Aug 2010, Boris Zbarsky wrote:
> 
> Elements behave fine.  The question is what the Window should do.  What 
> should window.parent return in the iframe while detached?  window.top? 
> What should window.resizeTo do?  That sort of thing.

I've fixed window.parent and window.top to return window.self, and made a 
few other fixes for things I'd overlooked.


On Thu, 26 Aug 2010, Boris Zbarsky wrote:
> 
> Again, nothing insurmountable, but there's a bunch of code in Gecko that 
> makes assumptions about when windows can and can't exist that would need 
> auditing.

Indeed, the spec had the same problem!


> I can't speak to the web compat aspects.

Yeah, that's the real question.


> [...] this does raise the question of when it's OK to gc the iframe.

This is defined. In particular, since the event loop stops processing 
tasks for the ungrafted nested browsing context, there's no risk of 
scripts suddenly running in its context, and there's no browser-managed 
strong reference to the browsing context (much like when a document goes 
into session history).


On Fri, 27 Aug 2010, James May wrote:
>
> Could the iframe be hoisted to the top level of its parent browsing 
> context?

This would be scary; top-level browsing contexts have various privileges 
that subframes don't have, and we wouldn't want to give them to a window 
that was invisible to the user.


On Thu, 26 Aug 2010, Boris Zbarsky wrote:
> 
> I don't think it's reasonable to gc the <iframe> element while leaving 
> the window inside alive due to it being referenced.  That introduces 
> races where frameElement could suddenly become null at some point 
> (possibly between two lines of the same script, or even partway through 
> some operation; for example GC can happen, even multiple times, during a 
> property get or set).  That would be pretty broken behavior.

The spec says that basically anything you can observe in the DOM is a 
strong reference, including e.g. frameElement. So there's no race 
condition here.


On Fri, 27 Aug 2010, Olli Pettay wrote:
>
> One thing not too clear in the "magic iframe" approach is that how 
> session history works; how is the session history from the iframe merged 
> to the new one, especially if the iframe moves to a new document.

This is as well-defined in the spec as it is for the case of sibling 
iframes that aren't ungrafted, actually.


> Another thing, which is more implementation depended problem, is that 
> how the plugin native widget reparenting works, in case the iframe uses 
> plugins.

This is already a problem since you can move an <embed> around directly.

-- 
Ian Hickson               U+1047E                )\._.,--....,'``.    fL
http://ln.hixie.ch/       U+263A                /,   _.. \   _\  ;`._ ,.
Things that are impossible just take longer.   `._.-(,_..'--(,_..'`-.;.'

Received on Monday, 6 December 2010 16:45:41 UTC