开发者

Multiple AJAX requests delay each other

I have a long polling request on my page. The script on the server side is set to timeout after 20 seconds.

So, when the long polling is "idling", and the user presses another button, the sending of that new request is delayed until the previous script times out.

I can't see anything wrong with the code on jQuery side. Why is the onclick-event delayed?

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

Could the "usleep" be the problem?

Multiple AJAX requests delay each other


If you use sessions in the AJAX handling functions, you may run in to an issue where the server is maintaining session data on disk. If so, the data may be locked by the first request, so each subsequent request ends up waiting for the session data file to be available before it proceeds. In effect, this makes asynchronous calls block one another, you end up with linear responses to the requests in chronological order - synchronous. (here's a reference article)

A PHP-specific solution is to use session_write_close (docs) to close out the session as soon as you don't need it any more. This allows other subsequent requests to proceed because the session data will be "unlocked". Other server-side languages manage sessions in different ways, but this is usually something you can manage or control through some mechanism.

Managing sessions can have some pitfalls. If you call session_write_close (or otherwise end a session) right before you return a response, then you aren't going to do yourself any favors because the session would have been unlocked as soon as the response was sent. Thus, it needs to be called as early as possible.In smaller projects, this isn't so bad because you often have a php script that just handles the request and dumps a response, but if you have a larger framework and your request handler is only a part of it, you'll have to explore a more top-level solution to non-blocking session usage so your subcomponents are not closing a session that the framework expects is still open.

One route is to go with database session. There are pros and cons to this solution which are beyond the scope of this answer - check Google for exhaustive discussion for your particular server-side language. Another route is to use a function that opens a session, adds a variable, then closes it. You risk race conditions with this solution, but here's a rough outline using PHP as an example:

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


This sounds consistent with the 2 request rule - browsers only allow two concurrent connections to the same host at any one given time. That having been said, you should be fine with a long poll (receive) and send channel. Are you starting the long poll after page load using $(function(){...? Are you sure the request is being delayed on the client, and not in the browser? What are you seeing in firebug?


One thing you can do, you can abort the running poll and run your request first and then again start the poll.

//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()
           }
    });
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜