2011-08-01 116 views
12

我的页面上有很长的轮询请求。服务器端的脚本在20秒后设置为超时。多个AJAX请求相互延迟

所以,当长轮询是“闲置”,并且用户按下另一个按钮时,发送该新请求将被延迟,直到前一个脚本超时为止。

我看不出jQuery端的代码有什么问题。为什么onclick事件延迟?

function poll() 
{ 
$.ajax({ 
    url: "/xhr/poll/1", 
    data: { 
     user_id: app.user.id 
    }, 
    type: "POST", 
    dataType: "JSON", 
    success: pollComplete, 
    error: function(response) { 
     console.log(response); 
    } 
}); 
} 

function pollComplete() 
{ 
    poll(); 
} 

function joinRoom(user_id) 
{ 
$.ajax({ 
    url: "/xhr/room/join", 
    dataType: "JSON", 
    type: "POST", 
    data: { 
     user_id: app.user.id, 
     room_id: room.id 
    } 
}); 
} 

<button id="join" onclick="javascript:joinRoom(2);">Join</button> 

############ PHP Controller on /xhr/poll 

$time = time(); 
while ((time() - $time) < 20) 
{ 
    $updates = $db->getNewStuff(); 

    foreach ($updates->getResult() as $update) 
     $response[] = $update->getResponse(); 

    if (!empty($response)) 
     return $response; 
    else 
     usleep(1 * 1000000); 

    return 'no-updates'; 
} 

“睡眠”是否会成为问题?

XHR Screenshot

+0

问题是否在localhost中? –

+1

用于AJAX调用的PHP代码是否使用会话? –

回答

23

如果你使用的AJAX处理功能的会议,您将运行到一个问题,即盘会话数据被第一个请求锁定,所以每个后续请求最终都会在会话数据继续前等待会话数据可用。实际上,这会使异步调用彼此阻塞,最终会按时间顺序对请求进行线性响应 - 同步。 (here's a reference article

一个解决方案是使用session_write_closedocs)尽快收出会话,你不需要它了。这允许其他后续请求继续进行,因为会话数据将被“解锁”。

但是,这也会令人困惑。如果您在回复回复之前致电session_write_close,那么您不会做任何好处,因为一旦回复发送,会话就会被解锁。因此,它需要尽可能早地被调用。如果您使用AJAX请求的后回式样式体系结构,这并不是那么糟糕,但是如果您有更大的框架并且您的请求处理程序只是其中的一部分,那么您将不得不探索更高级的解决方案到非阻塞会话使用,以便您的子组件不关闭框架期望的会话仍然处于打开状态。

一条路径是与数据库会话。这个解决方案的优点和缺点超出了这个答案的范围 - 请检查Google进行详尽的讨论。另一条路线是使用一个函数打开会话,添加一个变量,然后关闭它。你用这个解决方案冒险竞赛,但这里有一个粗略的概述:

function get_session_var($key, $default=null) { 
    if (strlen($key) < 1) 
     return null; 
    if (!isset($_SESSION) || !is_array($_SESSION)) { 
     session_start(); 
     session_write_close(); 
    } 
    if (array_key_exists($key, $_SESSION)) 
     return $_SESSION[$key]; 
    return $default; 
} 
function set_session_var($key, $value=null) { 
    if (strlen($key) < 1) 
     return false; 
    if ($value === null && array_key_exists($key, $_SESSION)) { 
     session_start(); 
     unset($_SESSION[$key]); 
    } elseif ($value != null) { 
     session_start(); 
     $_SESSION[$key] = $value; 
    } else { 
     return false; 
    } 
    session_write_close(); 
    return true; 
} 
+1

我没有完全使用你提出的解决方案,但提示'session_write_close()'是完善!我的请求正在使用会话,并禁用它们工作得很好。 –

+1

'session_write_close()'解决了我的问题,谢谢! –

1

这听起来与2请求规则一致的 - 浏览器仅允许在给定的任何一个时间在同一主机两个并发连接。如前所述,你应该在长期民意调查(接收)和发送频道方面表现良好。您是否在页面加载后使用$(function(){...?)开始长期民意调查?您确定请求在客户端而不是在浏览器中被延迟?您在萤火虫中看到什么?

+0

是的,我确定,因为请求甚至不会在萤幕上显示几秒钟。但是当轮询结束并从头开始时,请求就会出现,就像上面的屏幕截图一样。 –

+0

我单独测试了AJAX,没有进行轮询,花了大约800ms才完成。轮询运行时,总是需要2秒以上。 –

+0

我同意这里。虽然较新的浏览器允许更多(FF允许6和IE 8允许8我猜)。 – Mrchief

1

One你可以做的事情,你可以中止运行投票和首先运行您的请求,然后重新开始调查。

//make sure pollJqXhr.abort is not undefined 
var pollJqXhr={abort:$.noop}; 

function poll() 
{ 
    //assign actual jqXhr object 
    pollJqXhr=jQuery.ajax({youroptions}); 
} 

function pollComplete() 
{ 
    poll(); 
} 


function joinRoom(user_id) 
{ 
    //pause polling 
    pollJqXhr.abort(); 

    jquery.ajax({ 
      /*options here*/ 
      success:function() 
      { 
       /*Your codes*/ 

       //restart poll 
       poll() 
      } 
    }); 
} 
+1

似乎这是治疗的症状,而不是原因 –