2013-06-21 20 views
8

情況:
我正在使用$ .ajax()POST向PHP腳本發送請求,該腳本會將大約400,000-500,000行插入數據庫。這一貫持續大約3.5-4分鐘。 (在這段時間內,請求是PENDING)。

問題:
我需要一些方法來顯示頁面上的進步。 (比如一個 %)。我嘗試在每隔5秒左右檢查一次的setInterval中使用$ .ajax(),但它們似乎在第一個(較長)$ .ajax()完成時累積並全部通過。

問:
不是$。阿賈克斯()異步默認?這是否意味着請求可以以任何順序隨時發出,並且響應應該以任何順序隨時接收?這甚至與異步有什麼關係?有沒有辦法定期從一個請求中發回「半響應」?或者當有未決的請求/響應時,我不能發送和接收請求/響應? (看下面的真棒圖)

在此先感謝!

multiple requests http://kshaneb.com/reqres.png

+2

1爲曲線圖進行測試。 :)您是否考慮過分塊處理數據,即每隔10k行發送一個單獨的請求? –

+1

+1解釋。你是否嘗試過使用async true .. – sathish

+0

我同意上面的Zsolt,考慮將你的數據分成幾個更小的請求,可以給你更快的響應,也可以計算完成的請求數的%基數。同時在單個請求中上傳大量數據,雖然是異步,但也會導致性能下降。 –

回答

1

而不是做一個ajax後,你可以發佈到一個iframe,讓PHP產生增量輸出,並與flush命令發送。

// send a hash mark for every 1000 inserts 
$a = 0; 
while ($rec = getDataForNextInsert()){ 
     $a++; 
     // do insert 
     if ($a%1000 == 0) { echo '#'; flush(); } 
} 

然後也可以輪詢iframe的內容以爲最終用戶提供漂亮的顯示。

2

希望這有助於

$(function() 
    { 
     var statusElement = $("#status"); 

     // this function will run each 1000 ms until stopped with clearInterval() 
     var i = setInterval(function() 
     { 
      $.ajax(
      { 
       success: function (json) 
       { 
        // progress from 1-100 
        statusElement.text(json.progress + "%"); 

        // when the worker process is done (reached 100%), stop execution 
        if (json.progress == 100) clearInterval(i); 
       }, 

       error: function() 
       { 
        // on error, stop execution 
        clearInterval(i); 
       } 
      }); 
     }, 1000); 
    }); 
+0

你的AJAX調用不包含URL。也許它應該。 –

7

你的長期運行的AJAX調用可能打開服務器上的一個會話,因此接下來的所有請求被阻塞由於會話文件鎖。

問題: PHP默認寫入其會話數據的文件。當向啓動會話的PHP腳本(session_start())發出請求時,會話文件被鎖定。這意味着如果您的網頁向PHP腳本發出大量請求(例如,通過Ajax加載內容),則每個請求可能會鎖定會話並阻止其他請求完成。 其他請求將掛在session_start()上,直到會話文件解鎖。如果您的某個Ajax請求運行時間相對較長,那麼這一點尤其糟糕。

解決方案: 會話文件保持鎖定狀態,直到腳本完成或會話手動關閉。爲了防止多個PHP請求(需要$ _SESSION數據)阻塞,您可以啓動會話並關閉會話。這將解鎖會話文件並允許剩餘的請求繼續運行,甚至在初始請求完成之前。

此處瞭解詳情: http://konrness.com/php5/how-to-prevent-blocking-php-requests/

+2

[這將是更可取的](http://meta.stackexchange.com/q/8259)在這裏包括答案的重要部分(不僅是原因,還有解決方案),並提供鏈接供參考。 –

+0

謝謝@optimistiks。正如那篇文章中所建議的那樣,我在使用session_write_close()之前運行耗時的部分我的php腳本,並且......它正在工作!無論如何,在本地主機上。我確信當我把它全部推送到服務器時,會出現新的問題。再次感謝! – ksb86

1

我希望這將是對您有用

首先,你需要在你的PHP腳本來禁用輸出緩衝

@apache_setenv('no-gzip', 1); 
@ini_set('zlib.output_compression', 0); 
@ini_set('implicit_flush', 1); 
for ($i = 0; $i < ob_get_level(); $i++) { ob_end_flush(); } 
ob_implicit_flush(1); 

然後你需要在這個過程中迴應你從PHP中取得的進展,例如:

for($i=0;$i < 20;$i++){ 
    echo ($i > 0 ? "#":"").($i/20*100); 
    sleep(1); 
} 

然後,在JavaScript中,您需要監聽xhr readystate change事件,並在發生這種情況時,只需解析響應文本並根據需要顯示進度。

監聽事件:

$.ajaxPrefilter(function(options, _, jqXHR) { 
       if (options.onreadystatechange) { 
        var xhrFactory = options.xhr; 
        options.xhr = function() { 
         var xhr = xhrFactory.apply(this, arguments); 
         function handler() { 
          options.onreadystatechange(xhr, jqXHR); 
         } 
         if (xhr.addEventListener) { 
          xhr.addEventListener("readystatechange", handler, false); 
         } else { 
          setTimeout(function() { 
           var internal = xhr.onreadystatechange; 
           if (internal) { 
            xhr.onreadystatechange = function() { 
             handler(); 
             internal.apply(this, arguments); 
            }; 
           } 
          }, 0); 
         } 
         return xhr; 
        }; 
       } 
      }); 

和樣品AJAX請求的:

$.ajax({ 
        url: "test.php", 
        cache: false, 
        onreadystatechange: function(xhr) { 
         res = xhr.responseText.split("#"); 
         $("#id").html(res[res.length-1] + "% done<br/>"); 
        }     
       }).done(function(data) { 
         $("#id").append("all done!</br>"); 
        }); 
      }); 

與jQuery 1.5+

+0

它幫助了我,謝謝。你知道有關crossbrowser與這些代碼兼容性的問題嗎? – littlealien