Previous Entry Add to Memories Share Next Entry
Adopting an IFRAME
cananian

Warning: heavy geek content.

Google recently rolled out a new Gmail feature: if you pop open a new little compose or chat window, and then close your main window, the small child window doesn't go away.

This is a pretty esoteric little tweak, but the underlying functionality is quite profound: in order to make this feature work, the entire document context (all the JavaScript responsible for running Gmail's UI) needs to get teleported from the main window out into the child window. For speed and memory reasons, you don't want to run a copy of the main code in the child window — no, you want to wait until just before you close the main window and then instantly teleport the guts of the main window over to the child. How's Google doing that?

In the browser model, separate windows are usually separate security contexts, safely sandboxed from each other. So this magic teleportation trick is also creating a wormhole between the different security domains. My curiosity was piqued, but Google (both blog and search engine) was strangely silent on how their new trick was pulled off.

Here's the story I eventually discovered. Google had long been thinking about a way to make this feature work. Their initial proposal was something called GlobalScript (or sometimes, "SharedScript"). This proposal met resistance and a new simpler solution was found: the "Magic IFRAME".

The guts are hidden inside bug 32848 in webkit's bug tracker. You put all of your application's good stuff inside an <iframe> element — we've guessed that already. You pass your child window a copy of that IFRAME, something like:

function doSomethingCoolThatNeedsANewWindow() {
     var childWin = window.open(...);
     childWin.onload = function() {
         childWin.functionThatTakesScriptContext(mySharedIFrame);
     }
 }

Now, the crux: when your main window is about to close, you just adoptNode the shared <iframe>:

// adoptNode in this case does removeChild() internally
// but does not unload the content
childWin.adoptNode(mySharedIFrame);
childWin.body.appendChild(myShareIFrame);

Voila! This used to completely unload and reload the iframe, erasing the existing application context, but with this one small hack Chrome (and now Safari, too) suppresses the reload and allows the untouched <iframe> context to teleport over to the child.

This doesn't work on Mozilla yet. And it's a pretty ugly hack, tweaking the behavior in just this one narrow case. (And Mozilla is a little bit cranky about adoptNode() being used without an prior importNode().) But this hack also allows work-arounds for two other long-standing iframe-reparenting "bugs". It suggests that <iframe> is now the <module> tag Crockford wanted, especially now that the <iframe> can be sandboxed in various ways as well. By putting each piece inside an <iframe> you can now build a robust module system for browser JavaScript.


Doesn't work in 'dev' channel of Chrome?

ossandcad

2010-07-16 05:19 pm (UTC)

Thanks for the detailed analysis, but would you know if this works in the Dev channel of Chrome specifically 6.0.466.0 dev? If I try to close the Gmail main window with a chat window popped out then I get a message box asking if i want to 'stay' or 'leave' and if i 'leave' then the chat window will be closed. If i do 'leave' then the chat window does close. Would you know if I am doing something wrong?

Re: Doesn't work in 'dev' channel of Chrome?

cananian

2010-07-16 05:52 pm (UTC)

From the Chrome changelog for 6.0.466.0 it seems that webkit is at revision 62670 (search for "webkit roll" in the changelog). Support for adopting IFRAMEs was added in webkit 53871 according to the bug. So your version of Chrome should certainly include the support.

But I'm not a Google or Gmail engineer. There might be some other reason this isn't working for you — maybe there were problems when they released it, and so they turned the feature off in Gmail until they fix the problem. I don't know. Another mystery! Let me know if you find out anything.


The feature doesn't work with chat windows, but it should work with all other tearoffs.