The Future of Comet: Part 1, Comet Today

by Jacob RusDecember 11th, 2007


Comet is a giant hack. Even when it works flawlessly and efficiently, bringing us real-time interactive applications, deftly weaving around firewalls and browsers, avoiding unfriendly side effects, and cutting latency to near zero, it does so using mechanisms unforeseen by browser vendors, and unspecified by web standards.

A few years ago, before it was widely used, or had been named, Ajax was in the same boat. It relied on an obscure and proprietary object, the XMLHttpRequest (XHR), created by Microsoft, and only slowly adopted by other browsers, one at a time. Today however, Ajax through the XHR object is nearly universally supported, with at least 4 popular and interoperable implementations (XHR is a native JavaScript object in IE 7). It is specified by a W3C working draft and dozens of books have been written on the subject.

Comet, going forward, has the same potential for standardization and specification. The WHAT Working Group, in their Web Applications 1.0 spec, commonly known as HTML5, created a specification for server-sent events, along with an event-source element to be added to HTML. These mechanisms, like other Comet “transports” such as htmlfile ActiveX objects, “forever frame” iframes, or XHR streaming, allow a browser to open a persistent connection to a server, and receive events in real time as they are available. But unlike other transports, server-sent events would be straight-forward, standardized and vendor supported, sans negative side effects, and optimized for the task.

Server-sent events are currently only implemented by Opera, and that implementation is far from complete, requiring some finesse on the server side. But as other browsers adopt server-sent events, and the compatibility kinks are worked out of implementations, it will be possible to slowly decrease the number of transports a Comet server must implement for cross-browser compatibility, while increasing reliability and performance.

In this part 1 of 2, I’ll describe the existing transports, their benefits and their shortcomings.

Trade-offs of existing transports

At present, web applications using Comet have a choice of several Comet techniques, which generally fall into two categories—streaming and long-polling—and which have various trade-offs in features, browser-compatibility, and unpleasant side effects. No one transport is perfect, but using a combination of them it is possible to build a decent user experience, while keeping latency down and throughput up on the server side.

Orbited implements most of these transports, and is easily extensible to support the rest of them, or any custom transports.

“Forever-frame” iframe streaming

“Forever-frame” iframes provide the easiest-to-implement widespread Comet transport. On the client side, we open up an invisible iframe and set its source to our Comet server. Then on the server side, we send a series of script tags—each of which calls some predetermined callback function—wrapped in a never-ending HTML document. The client-side JavaScript sets up the event callback function to do whatever it likes with the event payloads.

This works because browsers render pages incrementally, as they arrive. Unfortunately, to start this incremental rendering, Safari requires a kilobyte of data at the beginning of the stream. In Orbited, we use 100 <span></span> tags for this. But at some point we’ll perhaps switch this to some tasteful ASCII art. Also, having a constantly loading iframe causes browsers to leave the loading bar visible indefinitely, a side effect which cannot be worked around in several browsers, and in some browsers continually shows a wait cursor. That said, this transport works in all browsers released in the last 10 years, so if user experience is less important than maximal compatibility, it can be a good choice.

htmlfile ActiveX object

The Gmail team, in their Google Talk project, figured out how to exploit a mysterious ActiveX object called “htmlfile” for their Comet streaming in Internet Explorer. It’s a bit tricky to implement, as Michael Carter explained, because on the client side, we must create one of these objects, open an iframe inside it which receives events as in the iframe streaming case, then carefully avoid the random-seeming limitations of Explorer’s garbage collector, or we’ll be cut off mid-stream. Also, it only works in Explorer. But if we are careful, it seems to work flawlessly back to at least IE 5.01, with no untoward side effects.

XHR multipart

Back in the days of the Netscape/Microsoft browser wars, so-called push technology was developed for streaming whole page updates to browsers, a technique widely used by “real-time” webcams of the day. Any page or image sent with a Content-type: multipart/x-mixed-replace HTTP header would be replaced in the browser as each multipart section arrived. When Mozilla adopted the XHR object, they added the same support for multipart streams in XHR responses. This means client-side JavaScript is called each time a new event arrives, and the contents of the responseText are replaced with the new content. Unfortunately, this transport only works in Gecko-based browsers, and does not alert the browser to severed connections.

XHR streaming

Recommended by Safari developers, the XHR streaming transport works by opening up an XHR request from the browser and sending a stream of events in some custom data format from the Comet server (Orbited calls its XHR streams application/x-orbited-event-stream). The XHR object triggers a callback each time new data arrives in the stream (with ready state 3), and that callback can parse the responseText to obtain each event. This transport works well in Webkit- and Gecko-based browsers (IE doesn’t trigger ready state 3 until the connection is closed), but the responseText does keep growing indefinitely as more events come in, so the connection should be restarted every once in a while. Also, custom format parsing in JavaScript could lead to bugs, and the stream requires an initial padding of 256 bytes of data before Safari will begin to trigger events.

XHR long-polling

Long-polling works differently than streaming. Instead of stringing together every event in a single indefinitely long server response, our server keeps each connection open until it has an event, but then closes it after sending a response. Then the browser immediately opens another connection, ensuring that the server can pass it events in real time. This is less effective than streaming transports with respect to bandwidth overhead and throughput; it works, however, in all recent browsers—without the ugly side effects of iframe streaming.

Script tag long-polling (“CometP”)

If we need completely cross-domain Comet, browser security policies render all of the previous transports inoperable. Instead, we must turn to “dynamic” script tags—sometimes called “JSONP”—in a method described by Alex Russell last year, which I call “CometP”. We use JavaScript to create a script tag, setting its source to our Comet server. This connection stays open until the server has new data to send, at which point the browser executes the script, and we open up another script tag to wait for the next event. The performance here is comparable to XHR long-polling, but this works across domains.

Flash and other plugins

All of the previous techniques, whether standards-based or proprietary, rely on native browser technologies. It is also possible to use a Flash, Java, or Silverlight socket to stream events from a server to browsers. This has the latency characteristics of other streaming transports, but doesn’t suffer from negative side effects, works in any browsers with the requisite plugin installed, and can probably be made to work across domains. Unfortunately, it relies on the presence of a third-party plugin, meaning it cannot work on every platform (iPhone anyone?), or whenever the plugin in question is turned off by the user, and might also be blocked by zealous firewalls which restrict traffic to port 80. Most of all, moving away from open web technologies leaves a sour taste in my mouth.

Stay tuned

With this impressive list of transports, we can cover all recent browsers (IE 5+, Safari 1.3+, Firefox 1.0+; plus Opera 8.5+ as described next time) without unseemly side effects, using our choice of streaming or long-polling, and can support browsers back much further than that, with a few usability niggles. Unfortunately, however, this requires careful implementation of our server code and browser-side JavaScript, which must coordinate to agree on a transport. This coordination problem, along with browsers’ cross-domain security policies, prevent us from using real-time sources in the kinds of mashups built from other web services. The barriers to entry for Comet are much higher than for non-real-time content, and success relies on loopholes in existing browser objects. Wouldn’t it be nice if every browser could receive event streams across domains securely and efficiently via a single mechanism? Wouldn’t it be nice if web authors could write the same straight-forward HTML and JavaScript for every browser, and send a single format from the server? Stay tuned for part 2, which plots a course to such a future.

21 Responses to “The Future of Comet: Part 1, Comet Today”

  1. Dave Johnson » Blog Archive » Ajax Alive and Kicking Says:

    [...] sign that Ajax still has some gas left. Even more recently there are developments around charting, comet, sound and widgets. For those reasons I am not convinced that new “RIA” frameworks like [...]

  2. Jacob Rus Says:

    Safari’s developers tell me that on Leopard, the 256-byte initial buffer may no longer be necessary for XHR streaming. If so, great! (I haven’t upgraded yet, as I want to make sure Orbited keeps working with Safari 2, and I don’t have a spare machine; if someone else wants to test this, feel free. :)

  3. ry Says:

    Don’t forget Ajax.pull, a prototype.js class that can read a stream of JSON objects (separated by semi-colons). (more info)

  4. Jacob Rus Says:

    that seems to be just a particular data format used in conjunction with XHR streaming. As I explained: “the XHR streaming transport works by opening up an XHR request from the browser and sending a stream of events in some custom data format from the Comet server”. This custom data format could indeed be a stream of JSON objects, if you want.

  5. Kris Zyp Says:

    Great article, looking forward to part 2.

  6. GregWilkins Says:


    XHR long polling does not close a connection. It simply terminates the persistent HTTP response on a long held TCP/IP connection. The connection does not need to be reopened, but a new HTTP request does need to be sent to start the next poll - but then an ack needs to be sent anyway, so a packet will be going from the client to the server regardless.

    The data sent by comet transports has to be framed. XHR long polling just uses HTTP to frame it. Other transports may use framing that uses less bytes - but I would maintain not significantly so.

    In my recent musing,
    I argue that any app that can’t handle the occasional latency blip of long polling is not really suitable to comet anyway as TCP/IP can always introduce much bigger latency blips.

  7. Jacob Rus Says:

    Greg: yeah, you’re right. I should have made sure to be precise in my language, and should probably have elaborated that the bandwidth and latency difference between long polling and streaming is often insignificant. As you say, it is only the request which is finished, and not necessarily the connection. With Keep-Alive, it is indeed possible to send multiple requests over a single connection.

    Michael did a good job explaining this stuff his November “musing”:

  8. Jose M. Arranz Says:

    Jacob Rus: With Keep-Alive, it is indeed possible to send multiple requests over a single connection

    Only two requests at this time (HTTP 1.1 dixit) :(

    I would like to see an HTTP 1.2 removing this limitation because is a problem for COMET applications using long-polling (is not a problem if you have only one page using COMET/long polling).

  9. Anf Says:

    [...] die in verschiedenen browsern laufen, was du dir dazu mal durchlesen k

  10. Comet Daily » Blog Archive » The Future of Comet: Part 2, HTML 5’s Server-Sent Events Says:

    [...] doesn’t have to be a hack. Currently, as we saw last time, Comet relies on undocumented loopholes and workarounds, each one with some drawbacks. We can make [...]

  11. Ajax Alive and Kicking « You can solve your problem here.. Says:

    [...] sign that Ajax still has some gas left. Even more recently there are developments around charting, comet, sound and widgets. For those reasons I am not convinced that new “RIA” frameworks like Flex, [...]

  12. Comet Daily » Blog Archive » Buzzword Overload Says:

    [...] an invisible iframe pointing at a Comet server, which then sends data back. Jacob discussed this in more detail a few weeks [...]

  13. What is COMET? (technical) — Says:

    [...] can be implemented today by several methods (taken from this great post by Jacob Rus about how Comet works today. Look there for the [...]

  14. Comet for Web Games - Comet JavaScript Rails - 3DM Design Says:

    [...] Rus’s The Future of Comet at Comet [...]

  15. Second Life Grid Architecture Working Group Meeting 2 — Says:

    [...] maybe we should do a meeting about transports at some point (to clarify: the problem is how the server sends events to the client because the server cannot initiate a connection because of firewall/NAT reasons. Thus the long-polling technique is discussed and actually already in use in Second Life. For more information look at this article by Jacob Rus explaining the techniques used for Comet. [...]

  16. Silverlight 2 WCF Polling Duplex Support - Part 1: Architecture « Peter McGrattan’s Weblog Says:

    [...] More commonly the term is used in context with browser-native technologies such as JavaScript but I have seen it used to include proprietary plugins such as Silverlight.  The browser-native implementations apply [...]

  17. (sorta) real-time updates, with Trinidad « Matthias Wessendorf’s Weblog Says:

    [...] The technology to ensure (sorta) real-time updates on your web app is called, COMET. This is a giant hack, basically. There are three common ways to actually implement it. Polling, Long Polling and [...]

  18. The Future of Comet: Comet Today « Vinay’s - Web Technology I/O Says:

    [...] by Vinay on September 25, 2008 Comet is a giant hack. Even when it works flawlessly and efficiently, bringing us real-time [...]

  19. PavingWays - mobile web applications : Node.js is Important. An Introduction Says:

    [...] our web servers would not fit to the demands that we had on the client-side during the last months. Comet and Ajax-Push is a big hack, HTML5 Web Sockets are knocking at our door and we want to do things like real time data [...]

  20. Node.js is Important. An Introduction - PavingWays Says:

    [...] our web servers would not fit to the demands that we had on the client-side during the last months. Comet and Ajax-Push is a big hack, HTML5 Web Sockets are knocking at our door and we want to do things like real time data [...]

  21. The Evolution and Future of Real-time Browser Push Says:

    [...] other solutions to the real-time browser push problem were introduced including the htmlfile ActiveX object for [...]

Copyright 2015 Comet Daily, LLC. All Rights Reserved