The Good and Bad of WebSockets over AJAX

Since deciding to use WebSockets instead of AJAX calls with Node.js I have discovered some interesting things. Some of these things are good, and some are bad.

The Good

WebSocket Data Typed

AJAX calls can only send String datatypes, which means that you have to cast all data to the correct datatype with server side code. This can be tedious, especially for Booleans. Sometimes they are send as a String of 'true' or 'false', other times it’s '1' and '0'.

WebSockets can send any datatype that the browser JavaScript can use, and since Node.js is server side JavaScript it can work with any of those same datatypes easily. This means sending Booleans no longer requires casting on the server, they just arrive as Booleans. Numbers arrive as numbers, Arrays as Arrays, Strings as Strings. You can even send complex objects.

If you work with MongoDB you get yet another layer of compatibility. Instead of casting values as they come out of a database, they are just always the correct datatype.

This means end to end you never have to cast variables into datatypes other than for validation. When sending from the client, receiving on the server, inserting in the database, and even pulling data from the database and sending back to a different client the datatypes remain the same.

WebSockets are FAST

WebSockets are faster than AJAX. Because the client side JavaScript establishes a connection to the server when the page loads there is no need to reestablish a connection to the server each time you want to send data. The client instead can just send data. I don’t have any statistics on this, but the difference has been very noticable. And for anyone thinking it may be the server side code, or database that have increased performance, I can tell you that it isn’t. I am running the same server side code, Node.js, and database, MongoDB, that I was before converting my application to using just WebSockets.

The Bad

Sessions are Tricky

Getting sessions to work between Express and Socket.IO was very tricky and has no obvious solution. I think this is more of a problem with Express and less with WebSockets in general, but it’s a problem I ran into, so it’s worth mentioning.

To fix this I used a library that connects Express’s session store and Socket.IO handshake session object. The library is called socket.io-session and can be installed from npm with the following.

npm install socket.io-session

Some configuration is required, but their GitHub documentation shows this very well.

However, one part it didn’t show was how to set and change session variables within a socket listener. After doing some research I realized that, unlike Express, socket.io-session doesn’t save session variables just by setting them. You have to call a save() method after you set them.

socket.handshake.session.someKey = 'someValue';			
socket.handshake.session.save();

WebSockets Success Functions

Remember AJAX success callback functions? They were great.

Too bad WebSockets don’t have those. This means it works more like a language like ActionScript. To pass data around you need to emit an event and listen for a callback.

A basic single user client side example might look like this.

// put this where your AJAX would go
socket.emit('some_event_from_client', {
	yourData : 'goes here'
});

socket.on('some_event_from_client_complete', function(data) {

	if (error) {
		// display some error message
		return;
	}

	// do your callback code here

});

And the basic server side code would accept that data and initiate the callback like so.

socket.on('some_event_from_client', function(data) {

	// do something

	if (err) {
		socket.emit('some_event_from_client_complete', {
			error : 'Your error message here'
		});
		return;
	}

	socket.emit('some_event_from_client_complete', {
		error : false,
		yourData : 'goes here'
	});

});

Of course you also have to consider that WebSockets can also inform multiple users in a room. Other users wouldn’t be using the complete event listener as they didn’t initiate the event. They need an second event listener for other events from the server. So, for real time multi-user applications your client side code would look like this.

// put this where your AJAX would go
socket.emit('some_event_from_client', {
	yourData : 'goes here'
});

socket.on('some_event_from_client_complete', function(data) {

	if (error) {
		// display some error message
		return;
	}

	// do your callback code here

});

socket.on('some_event_from_server_to_all', function(data) {

	// do something here for all users

});

Notice that I only check for an error in the complete callback. This is because there is no need to inform all users that one user created an error on the server. That would just confuse an infuriate them.

Overall I’m very happy with my switch to a complete WebSocket driven architecture, but it’s not without it’s problems. After overcoming those problems WebSockets are very easy to use and have numerous benefits over AJAX calls.