Node.js Workshop

Session 3 - 01/04/2016

http://bit.ly/nodejs-ws-3

The history

We want: Low latency, bi-directional, event driven messages. Historically called Comet

  • Hidden iframe: As events occur, the iframe is gradually filled with script tags, containing JavaScript to be executed in the browser.
  • Ajax long polling: Ajax request which may wait for data to be available before responding, immediately after the response another request is made.
  • Script tag long polling: Same idea as ajax but creating a script tag for every request.

Websockets

All these implementations were flawed since they failed to maintain a persistent connection with the server and receive asyncronous events directly from the server

Websockets: The HTML5 implementation

WebSocket is a protocol providing full-duplex communication channels over a single TCP connection.

Websockets

The raw implementation looks something like this:


let exampleSocket = new WebSocket("ws://www.example.com/socketserver", "protocolOne");
exampleSocket.onopen = function (event) {
  exampleSocket.send("Here's some text that the server is urgently awaiting!");
};
exampleSocket.onmessage = function (event) {
  console.log(event.data);
};

Websockets

So what's the support for this thing?

Socket.io

Enables realtime, bi-directional communication between web clients and servers. It has two parts: a client-side library that runs in the browser, and a server-side library for node.js. Both components have a nearly identical API. Like node.js, it is event-driven.

Socket.io

Primarily uses the WebSocket protocol with polling as a fallback option, while providing the same interface. Although it can be used as simply a wrapper for WebSocket, it provides many more features, including broadcasting to multiple sockets, storing data associated with each client, and asynchronous I/O.

Let's implement it!

<<<<<<< HEAD

npm i socket.io --save

Hooking into express

Socket.io can hook into express to learn which port to use and to serve its frontend library.


const server = app.listen(config.PORT, () => console.log(`Server listening on localhost:${config.PORT}`));
const io  = require('socket.io')(server);

Listening for a connection

When a new connection happens the socket variable passed on the handler represents the newly connected user. Any events emitted or received on socket refer only to a single user, on the other hand all events on io are broadcasted to all connected users.


io.on('connection', function (socket) {
	socket.emit('an event', {data: 'some payload'}); //This event is only sent to a singular user
  socket.on('another event', function(data) {
		io.emit('broadcast event', data); //This event is sent to everyone (broadcasted)
	});
});

A real example (backend)

Keep track and display the number of connected users.


let connected = 0;

const updateOnline = () => io.emit('online', { users: connected }); //Broadcast the number of connected users

io.on('connection', function (socket) {
	//On new connection increment the number of users
  connected++;
  updateOnline();

  socket.on('disconnect', function() {
		//On disconnect decrement the number of users
    connected--;
    updateOnline();
  });
});

A real example (frontend)

First of all, we need to include the frontend library.
We'll also add some HTML to display the information.



Online users:

A real example (frontend)

Then we can connect to the server and we're ready to listen and send events.


//public/js/main.js
var App = {
  init: function() {
    this.onlineEl = document.getElementById('online');
    this.socket = io.connect('http://localhost:9090');

    this.subEvents();
  },

  subEvents: function() {
    var that = this;

    this.socket.on('online', function (data) {
      that.onlineEl.innerHTML = data.users;
    });
  }
};
App.init();
Note: We don't have ES6 on the frontend for now

Exercise 1: The click counter

Using what we just learned create the code to keep track how many clicks in total a <button> receives, this should be in sync on all connected clients.

Live code

Exercice: Click counter

Implement a click counter that counts the clicks on a <button>, this must be syncronized on all connected clients.

What's the catch?

Websockets are often difficult to scale, specially if you broadcast.

Solution? Pusher

Pusher is websockets as a service, you connect your frontent to it, connect your backend and it takes care of the communication and the scale.

One more thing...

What if I tell you there's a tool out there that does all of what we implemented out of the box?

Meteor

Meteor it's a platform that allows you to build isomorphic real-time apps in a breeze.

What we learned today

  • Websockets: What they are, where they come from
  • Socket.io: How to implement it
  • Meteor: What it is, when and how to use it.

Thank you!

Check out the repo https://github.com/martip-sainsburys/nodejs-workshop.