• Web
  • Tutorial

WebSockets and the Real-Time Web

Ajax gave us a great improvement, which was the ability to make an HTTP request using just JavaScript. And when we get back a response-- like the next number in this case, 20-- we can update the part of the UI that we want to, and we don't have to refresh the entire page to get that response. So this is much, much better, and makes for a better responsive user interface.

But imagine if were are on Facebook and, in order to get the next set of comments for the photo you just posted, you have to click a Refresh button over and over again. Well, I would probably do that, but nonetheless, it doesn't seem like a great user experience. The problem is that the server has no ability to send data to the browser whenever it wants. The browser has to initiate the request. And then once the response comes down, we close the connection.

So in this video, I'm going to talk about WebSockets. And before we get to WebSockets, I'm going to lay out some of the history of the strategies that have been used to achieve this idea of real time communication between the server and the browser. So given that constraint that HTTP closes the connection once we've gotten a response, let's think up some strategies that we could use to simulate getting data from the server whenever we have some new data to get. So we want to think about the different strategies from the perspective of being an engineer that has to solve this problem.

Well, the first one that we could use is called polling. And so we could write some JavaScript that, say, every two seconds goes to the server and says, hey, do you have any new data? And if the server has data, then great. And if not, no big deal. Two seconds later, we poll again. Now, this strategy works OK. It's pretty robust. But it's a little wasteful, because it's possible that there's no data from the server, in which case we just made a kind of a silly request. And it also puts a little bit of an undue burden on the server to have to be responding to these polling requests every couple of seconds from every connected client or every connected browser.

So the second thing we could do, this is called long polling. Sometimes it's colloquially refer to as comet, so long polling. And the idea here is to open up a request to the server and then they just keep it open. So just keep it alive. And when the server has some data, it will send it down the wire.

So HTTP does allow us to keep the connection open, or keep it open until we've sent a response. And then once the server has some data, it sends it down the wire, and then closes the connection. Now what the browser has to do is to open up another connection. So it just opens up another connection, and then this one stays alive until there's some additional data, and then the server sends that down.

So it's a lot more efficient than polling, because we're not sending a request every two seconds. We're only sending a request after we've gotten some data. Now, it turns out that long polling, or comet, was the strategy that was used for a pretty long time, and it's still actually used in some cases. But there's something that we could do that would be better.

What if we could just keep a connection open all the time? A real time connection, if you will, that we could send data back and forth over. So you probably know by now that we have this technology called WebSockets. And let me clean this up a little bit.

And the idea of WebSockets is that we want to open up a socket connection with the server that just stays open the entire duration of the application. So these are called WebSockets. And so WebSockets is actually a different transport, so it's a different transport protocol. And what we do is open up a WebSocket connection with the server and then just keep it alive for the entire time that we're in the app. And we can send data up to the server, and the server can send data back down.

Now, WebSockets have actually been around for quite awhile, but they weren't really used widely until recently. And that's because, since it's a new protocol-- it's a new protocol-- the browser actually has to implement WebSockets. So the browser has to give us that functionality. And it turned out that for awhile that browsers were not agreeing on what the protocol should be, and some of the browsers implemented it and some of them didn't.

So it took a while for this protocol to mature to the point that we can write for this protocol reliably. But now, most of the modern browsers, as far as I know, do support WebSockets. And so in the rest of this video, let's go take a look at how we can add WebSocket support to our bare bones web application that we built in Node.js and get a sense for how they work.

The first thing we're going to do is install an NPM package called Socket.IO. Now, normally for these kinds of videos, I don't like to use third party libraries. But in this case, we would have to implement our own WebSocket server that implements the protocol, and that's quite complex and out of the scope of the video. So we are going to use this external library, and there's quite a few of them.

There's another one called soc.js. But I think Socket.IO is a good one, and it's easy to use. And so that's the one that we're going to use. So go ahead and install that one.

And when that process completes, open up the project in your favorite editor. I'll start us off in the server file. And the first thing we need to do is to create the WebSocket server. So I'll create a variable called io. And we'll assign to that variable the result of requiring Socket.IO. And I'm going to just require it right in line here, because we're only going to use it in this one place. And then I pass to that function a parameter, which is the server that we just created above.

Like most objects in Node.js, the io object can respond to or emit events. So we can call the respond to the connection event. So we'll say io dot on connection. And that event handler will get passed the socket of the connected user, and we're not going to do anything special here. I'll just print out that a user is connected.

Now let's say the server wants to send a message to this connected browser. It can do that by calling the emit method of the socket and providing some message. So the message key could be whatever we want, and then some value. So the value could be a string. It could be an object, an array, any kind of JavaScript type that we can send over the wire. And for now, we're not going to emit anything, but you can play around with this to see the messages that get sent.

Now, let's say you want to send a message to everyone who's connected. We can just call the emit method on the io object itself. And let's say we want to send down a new count. So I'm going to say that we're going to emit the count message. And the value is going to be the incremented-- or the value of the current count, and then we'll increment it when we're done.

Let's go ahead and send this message down to all the connected clients every two seconds. And so we'll use a set interval call. And we'll do the io dot emit call, and then we'll do that every two seconds. So a little ES6 6 syntax here with the fat arrows. So every two seconds, we're going to emit this count event or message down to our connected clients.

Next up, we need to go to the client application JavaScript code and connect to io and handle these messages. First, we need to get access to the client library that's going to allow us to connect to the server using WebSockets. The Socket.IO package provides us that. And we just need to link to it. So I've added this script tag up here, and notice that it goes to this route that we didn't create ourselves but Socket.IO created it for us. And so this gives us the JavaScript that we can use in the browser over here in our app.js file to connect to the server using WebSockets.

Now all we need to do to connect is we'll will just create a variable, call it socket, and we'll assign to that the result of calling the io function, which is provided to us by that client library. And I'm going with this up into another function just to make this a little bit more organized called Connect. And we'll connect once our dom is ready.

OK, if I want to send messages up to the server, I can call the emit method on this socket, and then send a message with some kind of value, just like we can from the server. And the way that we can handle messages that were sent from the server is we can use the on method and then respond to whatever the message key was that the server sent. So in this case, remember we sent a message called count. And so it looked something like this, emit count. And then we sent the actual value of the count.

Well, now we're responding to that count. And we'll say that when we get a count message. We're going to want to update our user interface. Now, I've gone ahead and created a function here called update count element. And it comes from the last video where we grab the count element on the page and then we just set its inner HTML to whatever the count happens to be. So let's go ahead and just call that method, update count element. And we'll pass in whatever we get from our server.

Oops, and let's just make sure that I call the connect method on start up so we actually kick off this process where we connect to the WebSocket server. And now let's start up the server-- or restart it, if you need to do that-- and head over to the browser. All right, a lot of cool things going on now. You can notice that every two seconds the server, which is over here on the right, is sending down a message with the updated count. And then our JavaScript is updating the user interface to reflect that count.

And then also notice the user connected message that we're printing out to the server log. So we have a bidirectional connection between the browser and the server. The other thing to notice is down in the Network tab of the debugger, you can click on the WebSocket tab here and then take a look at the messages that are getting sand from the server, and also up to the server. Notice that we're getting the messages with the count, with the updated counts.

So the WebSocket protocol is the foundation on which many real time web application frameworks are built. And I hope this gives you a better intuition about where we evolved from, how we got here, and how you can use WebSockets to communicate back and forth between the server and a browser.