WebSockets in Node.js

Jun 10, 2019

WebSockets are a tool for bidirectional communication between a browser client and a server. In particular, WebSockets enable the server to push data to the client. This is different from your standard HTTP request using fetch() or Axios because the server cannot communicate with the client unless the client sends a request first.

WebSockets are more flexible, but also are harder to implement and scale. WebSockets put more of a burden on the developer, so use them sparingly and only when you absolutely need them. In this article, you'll learn how to build a simple real-time chat application using WebSockets.

The WebSocket Server

The ws npm package is the de facto WebSocket library for Node.js. You can also use Socket.IO, but Socket.IO is a higher level framework on top of WebSockets rather than an implementation of the WebSocket protocol.

Below is a basic example of a WebSocket server that tracks all open sockets and sends inbound messages to all open sockets. You can think of this as a simple chat server: when one person sends a message, the server broadcasts the message to everyone listening.

const WebSocket = require('ws');
const server = new WebSocket.Server({
  port: 8080
});

let sockets = [];
server.on('connection', function(socket) {
  sockets.push(socket);

  // When you receive a message, send that message to every socket.
  socket.on('message', function(msg) {
    sockets.forEach(s => s.send(msg));
  });

  // When a socket closes, or disconnects, remove it from the array.
  socket.on('close', function() {
    sockets = sockets.filter(s => s !== socket);
  });
});

WebSocket Client in Node.js

A WebSocket connection has two components, a client and a server. In the above example, you created a server. Clients initiate a request to open a WebSocket connection, and servers respond to inbound requests to open WebSocket connections.

You can also create a WebSocket client in Node.js using ws. This is great for testing your WebSocket logic, although you can also use WebSockets for communication between backend services. Below is an example of a WebSocket client that talks to the above server.

let clients = [
  new WebSocket('ws://localhost:8080'),
  new WebSocket('ws://localhost:8080')
];

clients.map(client => {
  client.on('message', msg => console.log(msg));
});

// Wait for the client to connect using async/await
await new Promise(resolve => clients[0].once('open', resolve));

// Prints "Hello!" twice, once for each client.
clients[0].send('Hello!');

WebSocket Client in the Browser

Most modern browsers support WebSockets out of the box. In other words, you can use the WebSocket class in the browser without without ws or transpilers, unless you want to support Internet Explorer 9 or Opera Mini. Below is a screenshot from the caniuse.com section on WebSockets.

Below is an example of a chat page that connects to the above server:

<html>
  <head>
    <script type="text/javascript">
      const ws = new WebSocket('ws://localhost:8080');

      // Browser WebSockets have slightly different syntax than `ws`.
      // Instead of EventEmitter syntax `on('open')`, you assign a callback
      // to the `onopen` property.
      ws.onopen = function() {
        document.querySelector('#send').disabled = false;

        document.querySelector('#send').addEventListener('click', function() {
          ws.send(document.querySelector('#message').value);
        });
      };

      ws.onmessage = function(msg) {
        document.querySelector('#messages').innerHTML += `<div>${msg.data}</div>`;
      };
    </script>
  </head>
  <body>
    <h1>Chat</h1>
    <div>
      <input id="message" placeholder="Message">
      <button id="send" disabled="true">Send</button>
    </div>
    <div id="messages">
    </div>
  </body>
</html>

Note that WebSockets in the browser have slightly different syntax for waiting for the connection and receiving messages from the server. Instead of on('message', messageHandler), you should write onmessage = messageHandler.


More Node Tutorials