简体   繁体   English

Chrome无法处理jquery ajax查询

[英]Chrome not handling jquery ajax query

I have the following query in jquery. 我在jquery中有以下查询。 It is reading the "publish" address of an Nginx subscribe/publish pair set up using Nginx's long polling module. 它正在读取使用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(); 
            }
        });
    }

The code is part of a chat room. 该代码是聊天室的一部分。 Every message sent is replied to with a null rply (with 200/OK) reply, but the data is published. 发送的每条消息都以null rply(200 / OK)回复回复,但数据已发布。 This is the code to read the subscribe address as the data comes back. 这是在数据返回时读取订阅地址的代码。

Using a timeout all people in the chatroom are sending a simple message every 30 to 40 seconds, even if they don't type anything, so there is pleanty of data for this code to read - at least 2 and possibly more messages per 40 seconds. 使用超时,聊天室中的所有人都会每隔30到40秒发送一条简单的消息,即使他们没有输入任何内容,因此这段代码需要读取大量数据 - 每40秒至少有2条消息可能更多。

The code is 100% rock solid in EI and Firefox. 该代码在EI和Firefox中100%坚实。 But one read in about 5 fails in Chrome. 但在Chrome中,大约5个读取失败了。

When Chrome fails it is with the 46 seconds timeout. 当Chrome失败时,它会超时46秒。

The log shows one /activity network request outstanding at any one time. 该日志显示任何时候一个/活动网络请求未完成。

I've been crawling over this code for 3 days now, trying various idea. 我已经在这个代码上爬了3天了,尝试各种想法。 And every time IE and Firefox work fine and Chrome fails. 每当IE和Firefox工作正常而Chrome失败时。

One suggestion I have seen is to make the call syncronous - but that is clearly impossible because it would lock up te user interface for too long. 我看到的一个建议是使呼叫同步 - 但这显然是不可能的,因为它会长时间锁定用户界面。

Edit - I have a partial solution: The code is now this 编辑 - 我有一个部分解决方案:代码现在是这个

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); 
        }
    });
}

Result is sometimes the reply is delayed until the $delay (15000) happens, Then the queued messages arrive too quicly to follow. 结果有时会延迟回复,直到$ delay(15000)发生,然后排队的消息太快到达了。 I have been unable to make it drop messages (only tested with netwrok optomisation off) with this new arrangement. 我一直无法通过这种新安排删除消息(仅通过netwrok optomisation测试)。

I very much doubt that delays are dur to networking problems - all machines are VMs within my one real machine, and there are no other users of my local LAN. 我非常怀疑网络问题的延迟是什么 - 所有机器都是我真实机器中的虚拟机,并且本地局域网中没有其他用户。

Edit 2 (Friday 2:30 BST) - Changed the code to use promises - and the POST of actions started to show the same symptoms, but the receive side started to work fine! 编辑2(美国中部时间星期五2:30) - 更改代码以使用承诺 - 并且操作的POST开始显示相同的症状,但接收方开始正常工作! (????!!!???). (???? !!! ???)。 This is the POST routine - it is handling a sequence of requests, to ensure only one at a time is outstanding. 这是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();
        });
    }
}

About one action in 8 the call to handlechat.php will timeout and the alert appears. 关于8中的一个动作,对handlechat.php的调用将超时并显示警报。 Once the alert has been OKed, all queued up messages arrive. 警报一旦确定,所有排队的消息都会到达。

And I also noticed that the handlechat call was stalled before it wrote the message that others would see. 而且我还注意到,在写出其他人会看到的消息之前,手机呼叫已停止。 I'm wondering if it could be some strange handling of session data by php. 我想知道是否可能是一些奇怪的处理会话数据的PHP。 I know it carefully queues up calls so that session data is not corrupted, so I have been careful to use different browsers or different machines. 我知道它仔细排队呼叫,以便会话数据不被破坏,所以我一直小心使用不同的浏览器或不同的机器。 There are only 2 php worker threads however php is NOT used in the handling of /activity or in the serving of static content. 只有2个php工作线程,但是php不用于处理/活动或静态内容的服务。

I have also thought it might be a shortage of nginx workers or php processors, so I have raised those. 我也认为它可能是nginx工作者或php处理器的短缺,所以我提出了这些。 It is now more difficult to get things to fail - but still possible. 现在更难以让事情失败 - 但仍然可能。 My guess is the /activity call now fails one in 30 times, and does not drop messages at all. 我的猜测是/ activity调用现在失败30次,并且根本不丢弃消息。

And thanks guys for your input. 谢谢你们的投入。


Summary of findings. 调查结果摘要。

1) It is a bug in Chrome that has been in the code for a while. 1)Chrome中的一个错误已经在代码中存在了一段时间。
2) With luck the bug can be made to appear as a POST that is not sent, and, when it times out it leaves Chrome in such a state that a repeat POST will succeed. 2)幸运的是,可以将错误显示为未发送的POST,并且当它超时时,它会使Chrome处于这样一种状态,即重复POST将成功。
3) The variable used to store the return from $.ajax() can be local or global. 3)用于存储$ .ajax()的返回的变量可以是本地的或全局的。 The new (promises) and the old format calls both trigger the bug. 新的(promises)和旧的格式调用都触发了bug。
4) I have not found a work around or way to avoid the bug. 4)我没有找到工作或避免错误的方法。

Ian 伊恩

I had a very similar issue with Chrome. 我与Chrome有一个非常相似的问题。 I am making an Ajax call in order to get the time from a server every second. 我正在进行Ajax调用,以便每秒从服务器获取时间。 Obviously the Ajax call must be asynchronous because it will freeze up the interface on a timeout if it's not. 显然,Ajax调用必须是异步的,因为如果没有,它会在超时时冻结接口。 But once one of the Ajax calls is a failure, each subsequent one is as well. 但是,一旦Ajax调用之一失败,每个后续调用都是如此。 I first tried setting a timeout to be 100ms and that worked well in IE and FF, but not in Chrome. 我首先尝试将超时设置为100毫秒,这在IE和FF中运行良好,但在Chrome中却没有。 My best solution was setting the type to POST and that solved the bug with chrome for me: 我最好的解决方案是将类型设置为POST,并为我解决了chrome的错误:

   setInterval(function(){ 
      $.ajax({
         url: 'getTime.php',
         type: 'POST',
         async: true,
         timeout: 100,
         success: function() { console.log("success"); },
         error: function() { console.log("error"); }
       });
   }, 1000);

Update: I believe the actual underlying problem here is Chrome's way of caching. 更新:我认为这里的实际根本问题是Chrome的缓存方式。 It seems that when one request fails, that failure is cached, and therefore subsequent requests are never made because Chrome will get the cached failure before initiating subsequent requests. 似乎当一个请求失败时,该缓存会被缓存,因此后续请求永远不会发生,因为Chrome会在启动后续请求之前获得缓存失败。 This can be seen if you go to Chrome's developer tools and go to the Network tab and examine each request being made. 如果您转到Chrome的开发人员工具并转到“网络”标签并检查每个正在发出的请求,就可以看到这一点。 Before a failure, ajax requests to getTime.php are made every second, but after 1 failure, subsequent requests are never initiated. 在失败之前,每秒都会对getTime.php发出ajax请求,但是在1次失败之后,永远不会启动后续请求。 Therefore, the following solution worked for me: 因此,以下解决方案对我有用:

   setInterval(function(){ 
      $.ajax({
         url: 'getTime.php',
         cache: false,
         async: true,
         timeout: 100,
         success: function() { console.log("success"); },
         error: function() { console.log("error"); }
       });
   }, 1000);

The change here, is I am disabling caching to this Ajax query, but in order to do so, the type option must be either GET or HEAD, that's why I removed ' type: 'POST' ' (GET is default). 这里的变化是,我禁止缓存到这个Ajax查询,但为了这样做,类型选项必须是GET或HEAD,这就是我删除' type: 'POST' '的原因(GET是默认的)。

try moving your polling function into a webworker to prevent freezing up in chrome. 尝试将您的轮询功能移动到网络工作者,以防止铬合金冻结。 Otherwise you could try using athe ajax .done() of the jquery object. 否则你可以尝试使用jquery对象的ajax .done()。 that one always works for me in chrome. 一个人总是在我的铬合金。

I feel like getxhr should be prefixed with "var". 我觉得getxhr应该以“var”为前缀。 Don't you want a completely separate & new request each time rather than overwriting the old one in the middle of success/failure handling? 您是否每次都想要一个完全独立的新请求而不是在成功/失败处理过程中覆盖旧请求? Could explain why the behavior "improves" when you add the setTimeout. 可以解释为什么添加setTimeout时行为“改进”。 I could also be missing something ;) 我也可能遗漏了一些东西;)

Comments won't format code, so reposting as a 2nd answer: 评论不会格式化代码,因此重新发布为第二个答案:

I think Michael Dibbets is on to something with $.ajax.done -- the Deferred pattern pushes processing to the next turn of the event loop, which I think is the behavior that's needed here. 我认为Michael Dibbets正在使用$ .ajax.done - 延迟模式将处理推送到事件循环的下一轮,我认为这是需要的行为。 see: http://www.bitstorm.org/weblog/2012-1/Deferred_and_promise_in_jQuery.html or http://joseoncode.com/2011/09/26/a-walkthrough-jquery-deferred-and-promise/ 请参阅: http//www.bitstorm.org/weblog/2012-1/Deferred_and_promise_in_jQuery.htmlhttp://joseoncode.com/2011/09/26/a-walkthrough-jquery-deferred-and-promise/

I'd try something like: 我会尝试这样的事情:

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; ?> 
  });

  getxhr.done(function(reply){
    handleRequest(reply);
  });

  getxhr.fail(function(e){
    window.status="GET error " + e;
  });

  getxhr.always(function(){
    requestNextBroadcast();
  });

Note: I'm having a hard time finding documentation on the callback arguments for Promise.done & Promise.fail :( 注意:我很难找到Promise.done和Promise.fail的回调参数的文档:(

Perhaps it can be worked around by changing the push module settings (there are a few) - Could you please post these? 也许它可以通过改变推模块设置(有几个)来解决 - 你能发布这些吗?

From the top of my head: 从我的头顶:

  • setting it to interval poll, would kinda uglily solve it 将它设置为区间轮询,有点可以解决它
  • the concurrency settings might have some effect 并发设置可能会产生一些影响
  • message storage might be used to avoid missing data 消息存储可能用于避免丢失数据

I would also use something like Charles to see what exactly does happen on the network/application layers 我还会使用类似Charles的东西来查看网络/应用程序层上究竟发生了什么

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM