避免';脚本没有响应';使用反向AJAX/Comet


Avoiding 'Script not responding' with Reverse AJAX / Comet?

我有一个工作线程,它使用XMLHttpRequest向服务器发送数据请求。该请求指向一个php文件,该文件基本上检查客户端所拥有信息的当前完整性,如果客户端需要新信息,则发送该信息。否则,服务器将检查信息,直到客户端需要响应为止。在服务器响应之后,整个过程重复进行。

当浏览器意识到脚本没有响应并向用户提供停止脚本的选项时,就会出现问题。正如你所看到的,这不是预期的结果。那么,在不混淆浏览器的情况下,继续使用类似彗星的结构的最佳方法是什么呢?

编辑:我意识到为什么脚本挂起了,我重复了整个worker线程,而不是在线程内部的某个更深的地方重复。所以我想我现在的问题是,在这个过程结束后,从哪里重新开始。

<?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>

您的线路:

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

open()async参数设置为false,这意味着JavaScript执行流在该Ajax调用上完全停止,直到它完成。在同步调用解析之前,您的网页将完全冻结,由于您使用的是长轮询,因此在很长一段时间内不会发生这种情况。因此,浏览器的解释器会向您发送一个警告,说明脚本执行花费了相当长的时间。(这个警告也是完全合法的——在同步调用解决之前,您不能在页面上做任何事情。)

您需要使用request.open("GET", url, true);。只需移动Ajax调用后需要发生的任何事情,并将其放置在onreadystatechange回调中。当服务器最终响应时,updateState功能将启动。响应"彗星推送"(即服务器响应解析长轮询查询)时应该发生的任何事情都需要进入回调。

异步Ajax将允许脚本继续执行,并且不会导致JS解释器挂起。脚本流将直接经过长轮询查询,而不是等待长轮询查询得到解决,稍后将使用来自服务器的新信息调用onreadystatechange回调。

编辑:

JavaScript解释器只有一个线程。如果该线程长时间不间断地使用,浏览器将怀疑出了问题并发出警告。您的synchronousAjax调用占用了单个JS线程,直到服务器最终回复才释放。正如我之前所说,在这漫长的时间里,页面上不会发生任何其他事情。翻译接到那个电话时被卡住了。

使用同步Ajax,您的流如下所示:

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

考虑一下这种高级异步Ajax替代方案:

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

在第二个示例中,解释器可以休息一下,而不是等待Ajax请求得到解决。每当Ajax调用从服务器返回时,就会触发onreadystatechange处理程序函数。如果您的调用是同步的,则解释器在调用解析之前不执行任何操作。如果您的调用是异步的,那么解释器可以自由地做任何它喜欢的事情——包括休息,并且不会引起浏览器警告——直到调用解析并执行onreadystatechange处理程序。

您没有说明您正在使用什么技术来实现反向AJAX(HTTP轮询?HTTP流?WebSockets?其他什么?)如果您正在使用轮询,服务器应该立即响应,即使它"在这里没有什么新鲜事"。

如果你打开了一个连接,这可能会导致问题;HTTP将浏览器限制为两个同时连接到服务器。在这种情况下,浏览器和任何其他脚本只有一个连接可以使用;这可能会导致浏览器认为事情被阻止。一种标准的方法是为彗星交互创建一个单独的主机名。

如果您使用WebWorker,浏览器不会抱怨它被阻止。(但是,连接计数的问题仍然可能导致问题。)