Wednesday, March 11, 2015

Going to the Server?

In previous posts, I've talked quite a bit about how I use Websockets for sending data from the server to the browser. For asynchronous server-to-client "push" scenarios, it can't be beat. But what about client-to-server? Using classic AJAX to post data to the server is still prevalent, but you may not be surprised to learn that Websockets are more efficient for that use-case as well.

HTTP is expensive, even when it's going on asynchronously in the background of your pages. I wanted to see just how much more it costs in terms of time to send data to the server using a classic HTTP POST versus sending data over an open Websocket. I set up the following test.

First, I set up a Node application using Express and Socket.io.

var express = require("express");
var http = require("http");

var app = express();
var server = http.Server(app);
var io = require("socket.io")(server);

//------------ Socket.io stuff

var wFirstSeen = null;
var events = 0;

io.on("connection", function(socket) {
  
    socket.on("data", function(data) {

        if (!wFirstSeen) {
            wFirstSeen = new Date();
        }
        events++;

        if (events === 200) {
            console.log('websockets done in ' + ((new Date() - wFirstSeen)));
            events = 0;
            wFirstSeen = null;
        }

    });

});

//------------ web application route

var hFirstSeen = null;
var posts = 0;

app.post("/data", function(req, res, next) {

    if (!hFirstSeen) {
        hFirstSeen = new Date();
    }
    posts++;

    if (posts === 200) {
        console.log('http post done in ' + ((new Date() - hFirstSeen)));
        posts = 0;
        hFirstSeen = null;
    }

    res.sendStatus(200);

});

app.use(express.static('public'));

// ------------ start the listening

var srv = server.listen(3000, function() {
    console.log("listening on port %d", srv.address().port);
});

Then I made a test web page so my client could send data to the server.

<!doctype html>

<html lang="en">
<head>
  <meta charset="utf-8">
  <title>WS vs HTTP</title>
</head>

<body>

  <p>Pushes data to the server.</p>
  
  <div id="wsStatus"></div>

  <div id="httpStatus"></div>

</body>

<script src="https://code.jquery.com/jquery-1.11.2.min.js"></script>
<script type="text/javascript" src="/socket.io/socket.io.js"></script>
<script type="text/javascript" src="/test.js"></script>

</html>

Finally, here are the contents of my test.js file.

var sckt;
var data = {
    field1: "something",
    field2: 12,
    field3: false,
    field4: "whatnot"
}

function websocketTest() {

    $("#wsStatus").append("starting send");
    for (var x = 0; x < 200; x++) {
        sendWebsocketData();
    }
    $("#wsStatus").append("sends complete");

}

function ajaxTest() {

    $("#httpStatus").append("starting send");
    for (var x = 0; x < 200; x++) {
        sendAjaxData();
    }
    $("#httpStatus").append("sends complete");

}

function sendWebsocketData() {
    sckt.emit("data", data);
}

function sendAjaxData() {
    $.post("/data", data);
}

$(function() {

    sckt = io.connect();
    sckt.on("connect", function() {
        $("#wsStatus").append("socket connected");
    });

});

So my test was pretty simple. I send the same data object from the client to the server 200 times and print out how long it takes for the server to process. I have test methods set up for Websockets and HTTP post. After I bring up my test page in my browser and see that my websocket connects, I can execute the websocketTest function and the ajaxTest function. The server will print out the results, which are in milliseconds.

The results in my Eclipse console

The send via Websocket was quite a bit faster every time, which is what I had expected. Posts consistently took well over 200 ms, whereas the data could be transmitted by websocket in the 45 ms range. Definitely something to think about when designing a web application that will be sending a lot of data from the client to the server. Websockets are currently supported across most browsers, so using them in place of HTTP posts may be a viable option.

That's enough seriousness for today. In today's frog comic, I examine the push for self-driving automobiles.

Amphibian.com comic for 11 March 2015