【发布时间】:2012-07-02 14:49:25
【问题描述】:
我在 jquery 中有以下查询。它正在读取使用 Nginx 的长轮询模块设置的 Nginx 订阅/发布对的“发布”地址。
function requestNextBroadcast() {
// never stops - every reply triggers next.
// and silent errors restart via long timeout.
getxhr = $.ajax({
url: "/activity",
// dataType: 'json',
data: "id="+channel,
timeout: 46000, // must be longer than max heartbeat to only trigger after silent error.
error: function(jqXHR, textStatus, errorThrown) {
alert("Background failed "+textStatus); // should never happen
getxhr.abort();
requestNextBroadcast(); // try again
},
success: function(reply, textStatus, jqXHR) {
handleRequest(reply); // this is the normal result.
requestNextBroadcast();
}
});
}
代码是聊天室的一部分。发送的每条消息都会以空 rply(带有 200/OK)回复进行回复,但会发布数据。这是在数据返回时读取订阅地址的代码。
使用超时功能,聊天室中的所有人每 30 到 40 秒发送一条简单消息,即使他们没有输入任何内容,因此该代码有大量数据可供读取 - 至少 2 条甚至更多消息每 40 秒。
代码在 EI 和 Firefox 中是 100% 坚如磐石的。但是大约 5 次阅读中的一篇在 Chrome 中失败了。
当 Chrome 失败时,超时时间为 46 秒。
日志显示在任何时候有一个 /activity 网络请求未完成。
我已经在这段代码上爬了 3 天,尝试了各种想法。每次 IE 和 Firefox 工作正常而 Chrome 失败。
我看到的一个建议是让调用同步 - 但这显然是不可能的,因为它会锁定用户界面太久。
编辑 - 我有一个部分解决方案:代码现在是这样的
function requestNextBroadcast() {
// never stops - every reply triggers next.
// and silent errors restart via long timeout.
getxhr = jQuery.ajax({
url: "/activity",
// dataType: 'json',
data: "id="+channel,
timeout: <?php echo $delay; ?>,
error: function(jqXHR, textStatus, errorThrown) {
window.status="GET error "+textStatus;
setTimeout(requestNextBroadcast,20); // try again
},
success: function(reply, textStatus, jqXHR) {
handleRequest(reply); // this is the normal result.
setTimeout(requestNextBroadcast,20);
}
});
}
结果有时回复会延迟到 $delay (15000) 发生,然后排队的消息到达太快而无法跟进。使用这种新安排,我无法让它丢弃消息(仅在关闭 netwrok optomisation 的情况下进行测试)。
我非常怀疑延迟是由于网络问题 - 所有机器都是我的一台真实机器中的虚拟机,并且我的本地 LAN 没有其他用户。
编辑 2(英国夏令时星期五 2:30) - 将代码更改为使用承诺 - 动作的 POST 开始显示相同的症状,但接收方开始正常工作! (??????!!!???)。 这是 POST 例程 - 它正在处理一系列请求,以确保一次只有一个未完成。
function issuePostNow() {
// reset heartbeat to dropout to send setTyping(false) in 30 to 40 seconds.
clearTimeout(dropoutat);
dropoutat = setTimeout(function() {sendTyping(false);},
30000 + 10000*Math.random());
// and do send
var url = "handlechat.php?";
if (postQueue.length > 0) {
postData = postQueue[0];
var postxhr = jQuery.ajax({
type: 'POST',
url: url,
data: postData,
timeout: 5000
})
postxhr.done(function(txt){
postQueue.shift(); // remove this task
if ((txt != null) && (txt.length > 0)) {
alert("Error: unexpected post reply of: "+txt)
}
issuePostNow();
});
postxhr.fail(function(){
alert(window.status="POST error "+postxhr.statusText);
issuePostNow();
});
}
}
关于 8 中的一项操作,对 handlechat.php 的调用将超时并出现警报。一旦警报被确定,所有排队的消息都会到达。
而且我还注意到,handlechat 调用在写入其他人会看到的消息之前就停止了。我想知道它是否可能是 php 对会话数据的一些奇怪处理。我知道它会小心地将调用排队,以免会话数据损坏,所以我一直小心使用不同的浏览器或不同的机器。只有 2 个 php 工作线程,但是 php 不用于处理 /activity 或提供静态内容。
我也认为这可能是 nginx worker 或 php 处理器的短缺,所以我提出了这些。现在让事情失败变得更加困难——但仍然有可能。我的猜测是 /activity 调用现在失败了 30 次,并且根本不会丢弃消息。
感谢大家的意见。
调查结果摘要。
1) 这是 Chrome 中的一个错误,已经在代码中出现了一段时间。
2) 如果运气好,该错误可以显示为未发送的 POST,并且当超时时,它会使 Chrome 处于重复 POST 将成功的状态。
3) 用于存储 $.ajax() 返回的变量可以是本地的或全局的。新的(承诺)和旧的格式调用都触发了这个错误。
4)我还没有找到解决这个问题的方法或方法。
伊恩
【问题讨论】:
-
如果您怀疑这是 Chrome 的问题,它可能会帮助其他人了解您使用的版本。 jQuery 版本也是。
-
客户端Chrome 20.0.1132.47 m jquery 1.7.2 O/S 64位windows,服务端Ubuntu 11:04。
-
我一直在 Safari (5.1.7) 中对此进行测试,发现它有效。所以这不是 Webkit 问题。还尝试在 Chrome for Linux 的 20.0.1132.47 版本中出现问题。
-
我已将超时更改为 10 秒并删除了警报,因此如果读取未能找到任何数据,则会超时并重新发出。现在日志显示很多超时读取,但所有数据都通过了!看来,在 tmeout/abort 之后在 Chrome 中的清除设置很好,而在成功后重用它有时会以某种方式失败。它不是一个漂亮的解决方案,也不是高性能的 - 但也许是必要的。
-
说得太早了。它仍然会丢失消息。这是值得注意的,当发送后不久没有完成读取。我试图检测丢失的回复,并中止/重新发出读取。造成了多大的混乱!多次读取未完成,并反复发送失败 - 然后突然间,在大量背景读取中一切都清除了,留下两个未完成。看来 .abort() 并不总是中止消息。 :(
标签: javascript jquery google-chrome