使用反向AJAX / Comet避免“脚本无响应”?

时间:2012-07-11 16:38:10

标签: php javascript ajax comet reverse

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

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

编辑:我意识到为什么脚本挂起,我重复了整个工作线程,而不是重复在线程内部的某个地方。所以我想我的问题现在在完成后再次开始这个过程。

<?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 个答案:

答案 0 :(得分:1)

你的专栏:

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

async open()参数设置为false,这意味着JavaScript执行流程在Ajax调用完全停止,直到完成。您的网页完全冻结,直到同步呼叫结算,并且由于您使用长轮询,这将不会发生很长时间。因此,您的浏览器的解释器会向您发出警告,指出脚本执行时间过长。 (此警告也是完全合法的 - 在同步调用解决之前,您无法在页面上执行任何操作。)

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

异步Ajax将允许脚本执行继续,并且不会导致JS解释器挂起。脚本流不会等待长轮询查询解决,而是会向右移动,稍后将使用服务器中的新信息调用onreadystatechange回调。

修改

JavaScript解释器只有一个线程。如果长时间使用不间断该线程,浏览器将怀疑出现问题并发出警告。您的同步 Ajax调用会抓取单个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处理程序。

答案 1 :(得分:0)

你没有说你用什么技术来实现反向AJAX(HTTP轮询?HTTP流?WebSockets?还有其他什么?)如果你正在使用轮询,服务器应该迅速响应,即使它是“没有新来的“。

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

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