2011-08-01 114 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

似乎這是治療的症狀,而不是原因 –