2
\$\begingroup\$

I've been working with JavaScript and AJAX a lot in the past, and now I'm moving towards the backend and working with databases more. I want to update my game data in as close to real-time as possible in JavaScript.

Here is what I have been doing to update the data as frequently as possible (I simplified it):

function updateData() {
        var xmlhttp = new XMLHttpRequest();
        xmlhttp.ontimeout = function (e) {
            // XMLHttpRequest timed out. Try sending another request
            updateData();
        };
        xmlhttp.onreadystatechange = function() {
            if (this.readyState == 4 && this.status == 200) {
                // only keep the data after the leading { (in case errors are outputted) (SHOULD NOT HAPPEN)
                var data = this.responseText.slice(this.responseText.indexOf('{'));
                try {
                    data = JSON.parse(data); // we're expecting JSON data -- make this an object for us
                } catch (error) {
                    console.error("Error parsing data");
                }
                // handle data...
                // and repeat:
                updateData();
            }
        };
        xmlhttp.open("GET", "data_getter.php", true); // "?t=" + getTime() to endure that the data is not cached
        xmlhttp.send();
}
updateData();

I call the function updateData() once and then each time the previous request is received, the function gets ran again.

I am wondering if there is a better way to continually refresh data (or make the data on the game website as close to realtime as possible) than to send an AJAX request every time the previous one is received? This method means that there will be a delay of the time it takes for the server to load, but that isn't too much.

Is this the best practice? Or can you somehow open a connection to a PHP script that communicates with the server in realtime and not close the connection for the duration of the game?

\$\endgroup\$

2 Answers 2

1
\$\begingroup\$

Main question

Is this the best practice? Or can you somehow open a connection to a PHP script that communicates with the server in realtime and not close the connection for the duration of the game?

A better approach would be to use web sockets. That way the function doesn't need to run continuously but instead the front-end code can respond to data coming back from the server. PHP supports sockets and there are a few examples on the web - e.g. in PHP documentation, this chat application (which actually I don't recommend parts of - e.g. the global variables).

For example:

$(document).ready(function(){
    var websocket = new WebSocket("ws://exampleDomain.com/data_getter.php");
    websocket.onmessage = function(event) {
        var data = JSON.parse(event.data);
        //handle data
    };

The PHP code would likely need to utilize socket_create() && socket_send().


Other review points (about current code)

The current code sets ontimeout:

xmlhttp.ontimeout = function (e) {
    // XMLHttpRequest timed out. Try sending another request
    updateData();
};

this could be simplified to

xmlhttp.ontimeout = updateData;

Bear in mind that the event target e would be passed as the first argument to updateData so if a different set of arguments was needed it would require additional work - e.g. using Function.bind().


With the ready statechange handler, the function updateData() only gets called when the status code is 200

xmlhttp.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200) {

what if there is a different status code? Perhaps it wouldn't be wise to keep making requests to the server, but instead show an error message- e.g. invalid input (4xx) or server error (5xx).

\$\endgroup\$
2
  • \$\begingroup\$ I know this is a while later... but I finally got around to setting this up and I figured out it wasn't working because you have to enable websockets. I don't know much about PHP compile time, but is there a way to do this on my Apache/Bluehost server? \$\endgroup\$ Commented Apr 26, 2020 at 21:01
  • \$\begingroup\$ I am not familiar with Bluehost but I do see Bluehost.com has a Help Center. If you have an account then I would suggest contacting the bluehost support. \$\endgroup\$ Commented Apr 27, 2020 at 22:41
3
\$\begingroup\$

Reviewing your function

Looking at updateData() shows:

  1. (reading signature only) there's no return value. So it does something inside, potentially modifying state (outside your function scope)
  2. (reading body) it has two responsibilities: (1) retrieve data from server via http query; (2) actual update of variable data by assigning retrieved data to it.
  3. it calls itself in two conditional branches. In fact it's a recursive function.

Improve:

(1) The function could return retrieved data. This would make it a pure function representing query part (of CQRS).

(2) This violates CQRS. You could improve by separating query (http data retrieval) from command (updating state: assigning a new value to a variable).

(3) recursive calls of same HTTP GET request in order to keep state up-to-date are conceptually called long-polling. This polling is usually implemented as consecutive GET requests between intervals using a timer. To reduce unnecessary updates, the polling makes advantage of HEAD requests using modifiedSince header and E-tags (both telling if server has updated data or no change since last fetch). A resource-friendly alternative to long-polling is the use of web-socket protocol.

Web-sockets

An event-based communication between server and client via a dedicated socket-connection. This connection is opened once allowing bi-directional asynchronous text-messages. Thus the server can send an update-notification (either including updated data or to allow the client to retrieve data in a separate GET request).

There are web-socket libraries for both JavaScipt (client) and PHP (server).

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.