Note to self about Server-Sent Events

This post is more than 2 years old.

This morning I took a look over the Firefox 6 release notes. Before I go any further - wow - kudos to the Firefox devs for such a good, detailed, and informative set of release notes. I was really impressed. Anyway, while reading them I noticed they mentioned support for Server-Sent Events. This is one of the more interesting HTML5 specs as it allows for push notifications. In my simple testing though it seemed to fall back to simple polling, which is actually kind of cool. So for example, here is the HTML:

<html>

<head> <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script> <script type="text/javascript"> $(document).ready(function() {

	var source = new EventSource('test2.cfm');
	source.onmessage = function (event) {
	  console.log(event.data);
	};

}); </script> </head>

<body>

</body> </html>

Note - the jQuery here is completely unrelated. Note the EventSource object. Once create, you can listen to a few events (see the spec I linked to above), including an onmessage one. I built a simple CFM page to respond to the requests. According to the spec you have a few options on what you return, but the simplest is to just send data back. Data values must be prepended with data:. So to send back two lines of text, you would do:

data: Foo data: 9 data: beer

I began with this in ColdFusion:

data: <cfoutput>#randRange(1,100)#</cfoutput>

Which didn't work. Luckily, Chrome was very clear on why:

Maybe I'm jaded (ok, I am), but I don't expect the browsers to be this helpful. In fact, look at what Firefox will report:

Useless. Less then useless in fact as it may lead you to think ColdFusion is down. Any way, now that we know the content type is the issue, it is trivial to solve:

<cfcontent type="text/event-stream">data: <cfoutput>#randRange(1,100)#</cfoutput>

Any way, this is an interesting feature. If you follow me on Twitter you know I've been railing against HTML5 demos that aren't practical. (How many times has a client asked you to draw something that Canvas would help you with? How many times has a client asked for better form validation?) This one looks like it could be very interesting. Any of my readers using this in production yet?

Oh - and yeah - don't bother trying this in IE9.

Raymond Camden's Picture

About Raymond Camden

Raymond is a senior developer evangelist for Adobe. He focuses on document services, JavaScript, and enterprise cat demos. If you like this article, please consider visiting my Amazon Wishlist or donating via PayPal to show your support. You can even buy me a coffee!

Lafayette, LA https://www.raymondcamden.com

Archived Comments

Comment 1 by Jason Presley posted on 8/29/2011 at 7:10 PM

Is HTML 5 even ready for production? Seems like browser support was still very spotty. Other opinions?

Comment 2 by Raymond Camden posted on 8/29/2011 at 7:12 PM

It's very hit and miss. Things in the Form space, which to me are the #1 thing HTML can improve on (seriously - haven't web devs spent billions of hours with forms) is mostly good but COMPLETELY lacking in IE. Canvas is ok, but I've needed to dynamically draw something maybe once in the past ten years.

Other things work a bit better. Local storage is a nicer way to handle cookie type data. data-* attributes are real useful as well. The history stuff is also cool for Ajax apps.

Comment 3 by existdissolve posted on 8/29/2011 at 7:15 PM

Production? No. A little over a year ago, I developed a very simple chat interface using server-sent events, but *at the time* support was so limited (Chrome only), it wasn't worth bothering pursuing.

Now that FF supports it, though, I might revisit. Obviously, Internet Explorer won't support it until two-thousand-and-never, but there's nothing new about that...

Comment 4 by Anthony Webb posted on 8/29/2011 at 7:23 PM

Has anyone tried this in iOS or android browsers?

Comment 5 by Raymond Camden posted on 8/29/2011 at 7:25 PM

Give me 5 - I'll upload my simple demo and switch to updating a DIV.

Comment 6 by Raymond Camden posted on 8/29/2011 at 7:30 PM

http://www.coldfusionjedi.c...

This is interesting. I tried on my Xoom. No go! I tried on my iPad 2 - worked.

Comment 7 by Raymond Camden posted on 8/29/2011 at 7:31 PM

Tested on my Inspire as well - failed there. So looks like Chrome Mobile doesn't support it.

Comment 8 by Sagar Ganatra posted on 8/29/2011 at 8:35 PM

Ray,

I had posted on Server sent events some time back on my blog: http://www.sagarganatra.com..., good to know that it is now supported on FF6. This is better than polling since the EventSource object reconnects to the server side code every three seconds (on Chrome). If you add the open and close events on the EventSource object, you will be able to see these events getting invoked every 3 seconds. This can be changed on the server side by sending 'retry: 5000' (5 secs).

'text/event-stream' should be set as a content-type for Chrome and FF6 now. Opera expects it to be 'application/x-dom-event-stream', this maybe because it follows WHATWG specification and not W3C. IMO this can be used in production since many users are using Chrome or FireFox as their default browser, a fallback to polling on IE may suffice.

Comment 9 by Raymond Camden posted on 8/29/2011 at 8:40 PM

Thanks for sharing this Sagar!

Comment 10 by Phillip Senn posted on 8/29/2011 at 9:05 PM

Ray (and Sagar and others),

Thank you very much for blogging this. I had never heard of EventSource before. It looks like it could be done manually with a setTimeout function doing an Ajax call.

Is that correct, or am I missing the point?

Comment 11 by Raymond Camden posted on 8/29/2011 at 9:08 PM

I think one advantage is that - compared to setInterval - which you should be using instead of setTimeout - is that if one request takes 10 seconds to run, then it won't run more while it's waiting. Right Sagar?

Of course, setTimeout - if used in the event handler - would also handle that.

I think I read in the spec too that it can handle the mobile browser going to sleep and turn itself off?

Comment 12 by Sagar Ganatra posted on 8/29/2011 at 10:17 PM

Ray, Phillip,

From the server side, one can make the client wait. Consider this example which I have mentioned in my blog post. Once the EventSource establishes a connection with the server the open event is fired. Now the client is ready to receive any data that the server sends. On the server side one can have a loop that runs say 50 times and in each iteration it sends data to the client (use cfflush) and then sleeps for a second (cfthread action="sleep"). In this way the server side code has run for 50 seconds. Once the server completes its execution it closes and then reestablishes the connection.
Code:
<cffunction name="sendData">
<!--- Output time --->
<cfoutput>data: #timeFormat(now(), "medium")# #Chr(10)#</cfoutput>
<cfoutput>data: End of this message #Chr(10)#</cfoutput>
<!--- Mark the end of message --->
<cfoutput>#Chr(10)#</cfoutput>
<cfflush>
</cffunction>
<cfloop from="1" to="50" index="i">
<cfset sendData()>
<cfthread action="sleep" duration="1000"/>
</cfloop>

Comment 13 by Victor posted on 9/28/2011 at 3:51 PM

@existdissolve but there are pure javascript polyfill, that supports IE 8+, Firefox 3.5+ https://github.com/Yaffle/E... , cross domain request also supported

Comment 14 by Phillip Senn posted on 1/31/2012 at 8:04 AM

OK, I think I am getting the EventSource concept. PageA points to PageB. PageB loops and sleeps continuously on the server until it determines that PageA needs to be notified of something. It then produces a text/event-stream ouput, which calls back the message event in PageA. If PageB times out, then PageA will reopen the connection after X (3) seconds.
So there is still looping and sleeping going on - it's just that it's on the server now instead of the client using a setInterval.