我的页面上有一个很长的轮询请求。服务器端的脚本在20秒后设置为超时。
因此,当长轮询“空闲”并且用户按下另一个按钮时,新请求的发送将被延迟,直到前一个脚本超时。
我看不出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';
}
“usleep”可能成为问题吗?
答案 0 :(得分:25)
如果在AJAX处理函数中使用会话,则可能会遇到服务器在磁盘上维护会话数据的问题。如果是这样,则数据可能被第一请求锁定,因此每个后续请求最终等待会话数据文件在其进行之前可用。实际上,这会使异步调用相互阻塞,最终会按时间顺序对请求进行线性响应 - 同步。 (here's a reference article)
特定于PHP的解决方案是使用session_write_close
(docs)在您不再需要时立即关闭会话。这允许其他后续请求继续进行,因为会话数据将“解锁”。其他服务器端语言以不同的方式管理会话,但这通常是您可以通过某种机制管理或控制的。
管理会话可能会有一些陷阱。如果您在返回响应之前立即致电session_write_close
(或以其他方式结束会话),那么您不会给自己任何好处,因为会话在响应发送后就会解锁。因此,它需要尽早调用。在较小的项目中,这并不是那么糟糕,因为你经常有一个PHP脚本只处理请求并转储响应,但如果你有一个更大的框架和你的请求处理程序只是其中的一部分,您将不得不探索更高级别的非阻塞会话使用解决方案,以便您的子组件不会关闭框架所期望的会话仍在打开。
一种方法是使用数据库会话。这个解决方案的优点和缺点超出了这个答案的范围 - 请查看Google对您的特定服务器端语言的详尽讨论。另一种方法是使用一个打开会话,添加变量然后关闭它的函数。使用此解决方案可能会导致竞争条件,但这里是使用PHP作为示例的粗略概述:
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 :(得分:1)
这听起来与2请求规则一致 - 浏览器在任何给定时间只允许两个并发连接到同一主机。话虽如此,你应该对长轮询(接收)和发送频道都没问题。你是否在使用$(function(){...?页面加载后开始长轮询?你确定请求在客户端上被延迟了,而不是在浏览器中吗?你在firebug中看到了什么?
答案 2 :(得分:1)
您可以做的一件事是,您可以中止正在运行的民意调查并先运行您的请求,然后再次开始民意调查。
//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()
}
});
}