多个 AJAX 请求相互延迟
Posted
技术标签:
【中文标题】多个 AJAX 请求相互延迟【英文标题】:Multiple AJAX requests delay each other 【发布时间】:2011-10-17 17:08:50 【问题描述】:我的页面上有一个长轮询请求。服务器端的脚本设置为20秒后超时。
因此,当长轮询处于“空闲”状态,并且用户按下另一个按钮时,新请求的发送将延迟到前一个脚本超时。
我看不出 jQuery 端的代码有什么问题。为什么 onclick-event 会延迟?
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';
“睡眠”会是问题吗?
【问题讨论】:
本地主机也有问题吗?? 任一 AJAX 调用的 PHP 代码是否使用会话? 【参考方案1】:如果您在 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;
【讨论】:
我没有完全使用您提出的解决方案,但session_write_close()
的提示非常完美!我的请求正在使用会话,并且禁用它们效果很好。【参考方案2】:
这听起来与 2 请求规则一致 - 浏览器在任何给定时间只允许两个并发连接到同一主机。话虽如此,长轮询(接收)和发送通道应该没问题。您是否在使用 $(function()...
【讨论】:
是的,我敢肯定,因为请求甚至在几秒钟内都没有出现在萤火虫中。但是当轮询结束并从头开始时,请求就会出现,就像上面的屏幕截图一样。 我单独测试了 AJAX,没有轮询,大约需要 800 毫秒才能完成。轮询运行时,总是需要 2 秒以上。 我同意这里。虽然较新的浏览器允许更多(FF 允许 6 和 IE 8 允许 8 我猜)。 如前所述(有点),此问题主要与 IE 8 及以下版本有关 (weblogs.asp.net/mschwarz/archive/2008/07/21/…) 如链接中所述,但是,HTTP 规范建议客户端 应该 限制并发连接数。这就是为什么建议使用 CDN 的原因 - CDN 是一个不同的域名,因此可以让您绕过用户代理的并发限制。综上所述,我认为这不完全是 OP 的问题 :)【参考方案3】:您可以做的一件事是,您可以中止正在运行的投票并首先运行您的请求,然后再次启动投票。
//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()
);
【讨论】:
看来这是治标不治本以上是关于多个 AJAX 请求相互延迟的主要内容,如果未能解决你的问题,请参考以下文章