0

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>

2 Answers 2

1

Your line:

request.open("GET", url, false);

has the async argument of open() set to false, 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 the onreadystatechange callback. When the server finally responds, the updateState function 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 onreadystatechange callbacks 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:

send synchronous request
wait
and wait
and wait
(meanwhile, nothing else can get done)
and wait...
....
finally a response comes!
use the response to update the page

Consider this superior asynchronous Ajax alternative:

send ansyc request

[the interpreter sleeps and the browser is happy]

a response comes!
the request's readystatechange event fires now
the onreadystatechange handler uses the response to update the page

In the second example, the interpreter gets to take a break instead of waiting for the Ajax request to resolve. Your onreadystatechange handler 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 your onreadystatechange handler.

Sign up to request clarification or add additional context in comments.

6 Comments

But that's the thing, I have to wait to get a response otherwise the purpose of comet is void. If i set the value to true then the javascript returns a "null" value before the server gives it the real value.
I just edited my answer a bit -- does the new line "Just move anything that needs to happen after the Ajax call and place it inside the onreadystatechange callback." help you at all, or do I need to clarify further?
Well the only thing that would need to happen after the ajax call would be to call it again? I don't see anything else fitting there besides that. I also edited my post to include all the code, including html
If you're using long-polling, then when a call ends, you need to use any data that the server just gave you and issue a new long-poll. You should put your self.postMessage('ID :: ' + response); inside of updateState so it gets fired when your Ajax call terminates.
Wow that makes a lot more sense. I called getInfo(response) again after that calling self.postMessage() and it fixed the not responding error as well. Thank you for your quick and helpful response.
|
0

You don't say what technique you are using to implement reverse AJAX (HTTP polling? HTTP streaming? WebSockets? Something else?) If you're using polling, the server is supposed to respond promptly, even if it's "nothing new here".

If you're holding a connection open, this can cause a problem; HTTP limits a browser to two simultaneous connections to a server. In that case, the browser and any other scripts only have one connection to work with; this can cause the browser to think things are blocked. A standard approach to this is to create a separate host name for comet interactions.

If you use a WebWorker, the browser won't complain about it being blocked. (However, the issue of connection count could still cause problems.)

1 Comment

I posted the javascript code I used for making the connection. I am using an XMLHttpRequest. But the problem doesn't seem to be in the connection, that updates on time and with the right information. However the browser still thinks since there is no response (because there isn't) that something has gone wrong.

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.