多个AJAX请求相互延迟

F.P*_*F.P 13 ajax jquery xmlhttprequest long-polling

我的页面上有一个很长的轮询请求.服务器端的脚本在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';
}
Run Code Online (Sandbox Code Playgroud)

"usleep"可能成为问题吗?

XHR截图

Chr*_*ker 25

如果在AJAX处理函数中使用会话,则可能会遇到服务器在磁盘上维护会话数据的问题.如果是这样,则数据可能被第一请求锁定,因此每个后续请求最终等待会话数据文件在其进行之前可用.实际上,这会使异步调用相互阻塞,最终会按时间顺序对请求进行线性响应 - 同步.(这是一篇参考文章)

特定于PHP的解决方案是使用session_write_close(docs)在您不再需要它时立即关闭会话.这允许其他后续请求继续进行,因为会话数据将"解锁".其他服务器端语言以不同方式管理会话,但这通常是您可以通过某种机制管理或控制的.

管理会话可能会有一些陷阱.如果您session_write_close在返回响应之前调用(或以其他方式结束会话),那么您不会自己做任何好处,因为会话在响应发送后就会解锁.因此,它需要被称为早possible.In较小的项目,这是没有那么糟糕,因为你往往有一个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;
}
Run Code Online (Sandbox Code Playgroud)