Portable Comet? It’s the IFrame, Stupid!

Comet Takes to IE Like a Fish Takes to Acid

Comet – or HTTP Streaming, if you will – is a little sensitive when it comes to portability, and I’ll give you four guesses which major browser is causing the grief? Yeah, IE makes it difficult for two reasons: (a) IE’s XMLHttpRequest component doesn’t tell you anything about the response until the connection has closed – even if you try polling it instead of relying on onReadyStateChange, you’ll still get an empty string (Try it); (B) Okay, switch to plan B and inspect IFrame content – we can’t rely on onload, which is only called once at the end, so we must poll. But no, polling won’t help either, as the IFrame content remains empty until (you guessed it) the connection is closed. (Try it).

We’re Going Back, Way Back: Inline Script Tags

Don’t give up on the IFrame so fast … we’re closer than we think. Actually, the solution harkens back to one of the original Push techniques: outputting script tags with inline code (what the HTTP Streaming pattern calls “page streaming”). If you do that in your main document, the code will be executed immediately, and the same is true if you do that inside an IFrame.

I’m talking about a service that outputs stuff like this:

  1. <script type="text/javascript">
  2.     doSomething();
  3. </script>

So Make the Server Spit Out Inline Script Tags

The portable solution is this: Have the server continuously output script tags that call a known function in the parent frame. When you set the child IFrame’s source to point to this service, it will start evaluating the inline scripts as they pop out of the server. This happens to be one technique people have used for remoting for many years (I think Brent Ashley recently told me he was doing it in ?1999). The twist with Comet is that you *keep* doing it, and don’t actually close the connection for a while. (Again, I’m sure some people were doing that for a long time too!).

Is it elegant? No. It means the remote service is suddenly coupled to the client-side of the web app – it has to know something about what’s in the parent frame, whereas you’d often like it to be generic and just deliver a response in XML, JSON or whatever. Like most things Ajax, we’re using a hack because it nonetheless push all the right buttons for our users.

Try It. Portable Comet for the Masses

Here’s Some Code I Prepared Earlier

In the example above, the remote service outputs script tags in a loop – it’s a simple countdown service:

  1. <?
  2.   for ($i=$_GET["start"]; $i>=0; $i--) {
  3. ?>
  4.   <script type="text/javascript">
  5.     window.parent.onNewValue(<?= $i ?>);
  6.   </script>
  7. <?
  8.   }
  9. ?>

And in the browser’s initial Javascript, there’s a run-of-the-mill onNewValue() function, it looks something like this.

javascript
< view plain text >
  1. function onNewValue(i) {
  2.   statusDiv.innerHTML = i; // Paint the new value onto the page
  3. }

See what I mean about coupling? The server-side service had to know that there’s a Javascript function defined in the parent called onNewValue(). At least we’ve minimised the coupling by using an Observer/Event style indirection approach – evidenced by the simple call to “onNewValue()”. It would be worse if it was the script that actually performed application logic directly, repainting the DOM with the new value.

IFrame is the new XMLHttpRequest

Whoever put the X in Ajax ought to put an I in Comit. IE’s XHR component doesn’t provide the response until the connection has closed, and I don’t think version 7 changes that. Assuming (graciously) it happens in IE8, you’ll need to use IFrame for the next five years if you’re doing any Comet work. And of course, you won’t need to do that, because libraries will do it for you.

BTW You could argue that IE is doing the right thing by preventing access to the content until the connection is closed. Maybe they are, maybe they aren’t. From a pragmatic perspective, though, portable Comet requires Ajax. Alternatively, use IFrame with IE and XmlHttpRequest with the others, though I’m not sure if there’s much mileage to be gained from this hybrid strategy.

12 thoughts on Portable Comet? It’s the IFrame, Stupid!

Comments are closed.

  1. 1998/99 was when I built my first live ajax-style grid with in-place paging.

    The script tag stuff first crossed my radar in 2002 when Danne Lundqvist described it at:

    http://dotvoid.com/view.php?id=13

    You can see some of the history of these techniques in my Ajax Experience presentation wiki here:

    http://www.ashleyit.com/ajax/AjaxExperience.htm#%5B%5BBrowser%20Native%20Transports%5D%5D

    I also yammer on about transport layer evolution here:

    http://www.ashleyit.com/blogs/brentashley/2006/06/06/ajax-transports-still-need-to-evolve/

  2. You could have the server side iframe’s src take a parameter which is the name of the javascript function in the parent window to call (ala JSONP). This would get around the fact that the server has to be coupled to the client by having a known function name.

  3. From what I can tell the Dojo guys propose to decouple things by using their topic event system. The iframe updates the topic with each script tag and any subscribers to this topic are updated. Again the topic needs to be known about but it it’s a bit more elegant (particularly if something fails) than directly calling a function.

  4. TI, It’s a fair point…Alex’s original Comet article doesn’t only talk about streaming, but also about a distributed event model (as in Twisted). I guess the JSON-P method is a kind of Comet-lite.

  5. I found this column when I was searching for info about IFrames and AJAX. I am trying to build a authorization wrapper around an application. This wrapper either displays a login or the application in an IFrame with a logout button added.

    I’m having problems making the logout button display only when the application IFrame is visible, and to call the wrapper authorization logout routine.

  6. Wow, to be honest…you seem to jump to conclusions alot.

    The only part I accept is valid is about AJAX and IE, but to be frank…you CAN stream information using XML & ActiveX objects in IE, it’s not the most idealistic as it would require alot of extra coding and unnecessary debugging failsafes (not going to get into too much detail, as it’s not even considered part of AJAX).

    Well, to the point, cross-bowser streaming CAN be done using long polling, feel free to look at this link to an example in which the server streams the command at a 5 second delay: http://www.sentertainment.net/development/ajax/long_polling/

    http://www.sentertainment.net/blog/