How to add Real Time synchronization for your Express Web Apps with WebSockets

Web development is great, however traditional web technologies have some limits. You often need to exchange more information with the server once the web page is loaded.

Then you probably use AJAX. However, you might soon discover that there are two limits with AJAX.

First, you don’t get any information unless you ask for it. There is no way with AJAX with that, the server cannot initiate the request by itself.

Second, AJAX requests are expensive. They are full blown HTTP requests with all the headers, handshaking process and everything else in between. Sometimes, you only need to exchange very little information, very quickly, with high frequency.

AJAX might still work but it will be very heavy on your servers to handle that many requests from not so many users.

Wouldn’t it be nice:

  • to receive notifications from the server without asking for them
  • to be able to send a lot of messages to the server without choking it to death

Welcome WebSockets. Websockets is a protocol providing full duplex communication over TCP.

But what does this mean? It means the following

  • Once initiated it does not rely on HTTP
  • The connection does not end after a single request
  • It can receive and send a lot of messages over the same connection
  • The server can send messages to the clients without being asked first
  • Every message and the connection itself is light weight, so a single server can work with multiple clients who send and receive a lot of messages

This is also called real time communication.

Who needs realtime communication?

WebSockets are all very nice but the web has survived so far without them. Do we really need them?

They can solve some hard and some not so hard problems in an elegant way. For example, gaming in the browser often requires a lot of communication between the browser and the server. Sometimes exchanging hundreds of messages in less than a second in both ways.

The most common example that you can find over the web is chap applications, because it requires you to exchange messages in both ways and the user expects to immediately in real time to be notified about any new message.

Realtime monitoring, like web page analytics, or server health is another place where you have to receive a lot of events from the server without asking for them.

One last example where WebSockets are often used is for synchronization between web apps and mobile apps. You might have your app, open on the web and on your phone. When you change something on your phone, you would like to immediately see the change over the web, too.

These are just a few examples and there are other places where this can be useful, too.

Socket.io

There are many ways to use WebSockets and there are many cool modules that you will find on NPM, but we are going to use Socket.io.

$ npm install socket.io

This module is much more powerful than just pure WebSockets. First, if for some reasons your client browser doesn’t support WebSockets it transparently uses other methods to connect and it is all transparent for you.

Another cool feature is the notion of channels, where over the same connection you can listen to different “channels” and react differently.

One last feature is reconnecting. By default, when you lose connection with your clients the browser does not try to reestablish it. However, socket.io takes care of that for you.

There are many more other features, but this is all you need to know for now.

Let’s talk

Let’s have a look at an Express app and how it will be working with socket.io. It’s an Express app which uses jade for templating language.

To install its dependencies

$ npm install jade express socket.io

This is how your server side code might look like

var http = require('http')
  , express = require('express')
  , app = express()
  , server = http.createServer(app)
  , io = require('socket.io')(server)

app.engine('jade', require('jade').__express) //__

app.set('view engine', 'jade')

app.get('/', function (req, res) {
  res.render('home')
})

var count = 0

io.on('connection', function (socket) {
  count++

  io.emit('news', { msg: 'One more person is online', count: count })
  socket.emit('private', { msg: 'Welcome you are the ' + count + ' person here' })

  socket.on('private', function (data) {
    console.log(data);
  })

  socket.on('disconnect', function() {
    count--
    io.emit('news', { msg: 'Someone went home', count: count })
  })
})

server.listen(3000, function() {
  console.log('Listening on port 3000...')
})

As you can see this app is very short but it is already doing a lot of things.

First, it takes only one line to use WebSockets with your Express application.

  , io = require('socket.io')(app)

When someone connects over WebSockets the app welcomes him and then it tells everyone (including him) that there is one more person online.

When the person disconnects, everyone is also notified.

You can see that you should use io.emit when you want to tell something to everyone and socket.emit when you only want to talk to specific connection.

socket is returned in the callback of the connection event.

The connection and disconnection events are provided by socket.io but you can also have your own custom event/channels.

In the example above, the app is listening for the private event and it is sending news and private events to the user. Those type of events/channels are custom and defined by the developer. You can have as many custom events/channels as you like.

Now let’s see how this app looks on the other side, from the client perspective. I am using Jade for our template language.

doctype html
html
  head
    title Learning WebSockets with Socket.io
  body
    h1 Messeage Board
    ul#messages
  script(src='/socket.io/socket.io.js')
  script.
    var socket = io.connect('http://localhost:3000')

    socket.on('news', function (data) {
      var li = document.createElement('li')
        , text = document.createTextNode('News: ' + data.msg + ' (' + data.count + ')' )

      li.appendChild(text)
      document.getElementById('messages').appendChild(li)
    })

    socket.on('private', function (data) {
      var li = document.createElement('li')
        , text = document.createTextNode('Private: ' + data.msg)

      li.appendChild(text)
      document.getElementById('messages').appendChild(li)

      socket.emit('private', {msg: 'Thank you for your message'})
    })

You can see from this little piece that that using WebSockets with socket.io on the client side is just easy as on the server side.

Maybe you are wondering where this comes from

  script(src='/socket.io/socket.io.js')

You haven’t defined such a path above in the app? Nope, but this path and file exist.

They are automatically defined by socket.io when you hooked it with your app. It provides everything you need to communicate efficiently over WebSockets and much more.

Listening and sending events is almost the same as on the server side. You have your socket, you can send all kind of events and you can also listen to all kind of events.

It’s not all roses

WebSocket is not perfect. First and foremost it is a different protocol over HTTP and some of your clients might not support it.

Second, even when they do support it your hosting provider might not.

Last, the traditional web is great for many things, so you should be careful when you choose to use WebSockets.

They might be lightweight but they are still connections to your server which stay open for a long time. They might saturate the ability of your server to accept new connections.

When you don’t need real time always on connection, don’t use one.

Next

Today I showed you how to use WebSockets with the great ‘socket.io’ but for many uses cases it might be too much.

Checkout lighter modules which have less features but might also be a better use case for you.

Next time I will talk about Server Sent Events(SSE). They are the smaller and simpler brother of WebSockets and often all you need.


Other articles that you may like

Did you like this article?

Please share it

We are Stefan Fidanov & Vasil Lyutskanov. We share actionable advice about development with Node, Express, React and other web & mobile technologies.

It is everything that we have learned from years of experience working with customers from all over the world on projects of all sizes.

Let's work together
© 2024 Terlici Ltd · Terms · Privacy