I have a worker thread that sends out a request to the server for data using an XMLHttpRequest. That request points to a php file that basically checks the current integrity of the information that the client has and if the client needs the new information then it is sent. Otherwise the server checks information until the client needs a response. After the server responds the whole process is repeated.
The problem arises when the browser realizes the script isn’t responding and gives the user the option to stop the script. As you can see, this isn’t the intended result. So what’s the best way to continue using the comet-like structure without confusing the browser?
EDIT: I realized why the script is hanging, I repeated the whole worker thread instead of repeating the somewhere deeper inside the thread. So I guess my question now where to start the process again, after it finishes.
<?php
//Client sends their current id
if(isset($_GET['id']))
$id = $_GET["id"];
//if id doesnt match servers id send them a new one
//other wise do not respond
$server_id = file_get_contents("ids.txt");
while($server_id == $id){
$server_id = file_get_contents("ids.txt");
sleep(1);
}
echo $server_id;
?>
Javascript:
self.addEventListener('message', function(e) {
var data = e.data;
switch (data.cmd) {
case 'start':
getInfo(data.id);
self.postMessage('ID :: ' + response);
break;
default:
self.postMessage('Unknown command');
};
}, false);
var response = null;
var request = new XMLHttpRequest();
function getInfo(inputID){
var url = "serverResponse.php?id=" + inputID;
request.open("GET", url, false);
request.onreadystatechange = updateState;
request.send(null);
}
function updateState(){
if(request.readyState == 4){
if(request.status == 200){
response = request.responseText;//getInfo(data.id);
}
}
}
html:
<html>
<script type="text/javascript">
function sayHI() {
var id = "666";
worker.postMessage({'cmd': 'start', 'id' : id});
}
var worker = new Worker('AjaxWorker.js');
worker.addEventListener('message', function(e){
document.getElementById('result').textContent = e.data;
//Some data has been received so go ahead and make another call to the server
//This is where the script hangs because the worker waits for a response
sayHI();
}, false);
</script>
<body>
<button type="button" name="submit" id="submit" onclick="sayHI()">Submit</button> </br></br>
<output id="result" name="result">Result</output>
</body>
</html>
Your line:
has the
asyncargument ofopen()set tofalse, meaning that the JavaScript execution flow completely stops on that Ajax call until it completes. Your webpage is completely frozen until that synchronous call resolves, and since you’re using long polling, that won’t happen for a very long time. Thus, your browser’s interpreter sends you a warning that script execution is taking a suspiciously long time. (This warning is completely legitimate, too — you can’t do anything at all on your page until the synchronous call resolves.)You need to use
request.open("GET", url, true);. Just move anything that needs to happen after the Ajax call and place it inside theonreadystatechangecallback. When the server finally responds, theupdateStatefunction will fire. Anything that should happen in response to a “comet push” (i.e. the resolution of a long-poll query by a response from the server) needs to go in that callback.Asynchronous Ajax will allow the script execution to continue and won’t cause your JS interpreter to hang. Instead of waiting for the long-polling query to resolve, the script flow will move right past it, and at some later time the
onreadystatechangecallbacks will be called with new information from the server.EDIT:
The JavaScript interpreter only has one thread. If that thread is utilized nonstop for a long period of time, the browser will suspect something has gone wrong and issue a warning. Your synchronous Ajax call grabs the single JS thread and doesn’t let go until the server finally replies. As I said earlier, during that long time, nothing else can happen on the page. The interpreter is stuck on that call.
With synchronous Ajax, your flow looks like this:
Consider this superior asynchronous Ajax alternative:
In the second example, the interpreter gets to take a break instead of waiting for the Ajax request to resolve. Your
onreadystatechangehandler function is fired whenever the Ajax call comes back from the server. If your call is synchronous, the interpreter does nothing until the call resolves. If your call is asynchronous, the interpreter is free to do anything it likes — including rest and not cause a browser warning — until the call resolves and it executes youronreadystatechangehandler.