2010-04-12 41 views
3

我有一個腳本,需要幾秒鐘的處理,最多約一分鐘。該腳本調整圖像數組的大小,銳化它們並最終將其壓縮以供用戶下載。jQuery.post動態數據回調函數

現在我需要某種進度信息。 我一直在想,用jQuery的.post()方法,回調函數的數據會逐步更新,但這似乎不起作用。

在我的例子,我只是使用一個循環來模擬我的腳本:

 $(document).ready(function() { 
      $('a.loop').click(function() { 
       $.post('loop.php', {foo:"bar"}, 
       function(data) { 
        $("div").html(data);       
       }); 
       return false; 
      }); 
     }); 

loop.php:

for ($i = 0; $i <= 100; $i++) { 
    echo $i . "<br />"; 
} 
echo "done"; 

回答

5

更新:獲取進度信息,因爲jQuery的阿賈克斯容易得多請求有一個承諾接口。使用這樣的回答:

https://stackoverflow.com/a/32272660/18771


下原來的答案是過時(它最初是從2010)。它仍然有效,但比它需要更復雜。我會保留它以備參考和比較。


你需要某種形式的從服務器的進展信息。 ajax回調沒有進行性的工作,只需要一次 - 在請求成功返回之後。

所以...在PHP中,你需要這樣的事:

/* progress.php */ 
$batch_done = some_way_to_find_out_that_number(); 
$batch_size = some_way_to_find_out_that_number_too(); 
header('Content-type: application/json'); 
// TODO: format number 
echo '{"progress":'. ($batch_size==0 ? '0' : $batch_done*100.0/$batch_size).'}'; 

對於這個工作,你的圖像處理腳本必須離開的當然是它的一些進展的證據。

而在JavaScript中是這樣的:

$(document).ready(function() { 
    $('a.loop').click(function() { 
    var queryData = {foo:"bar"}; 
    // prepare a function that does cyclic progress checking 
    var progressCheck = function() { 
     $.getJSON(
     "progress.php", queryData, 
     function(data) { 
      $("div.progress").css("width", data.progress+"%"); 
     } 
    ) 
    }; 
    $.post(
     'loop.php', queryData, 
     /* create the post request callback now */ 
     function(intvalId){ 
     return function(data) { 
      $("div").html(data); 
      clearInterval(intvalId); 
     } 
     }(setInterval(progressCheck, 1000)) 
    ); 
    return false; 
    }); 
}); 

這部分需要一些解釋:

function(intvalId){ 
    return function(data) { 
    $("div").html(data); 
    clearInterval(intvalId); 
    }; 
}(setInterval(progressCheck, 1000)) 

function(intvalId)是一個匿名函數,有一個參數 - 間隔ID。此ID用於停止通過setInterval()設置的時間間隔。幸運的是,撥打setInterval()返回這個ID。

匿名外部函數返回一個內部function(data),這個將是$.post()的實際回調。

我們立即調用外部函數,在這個過程中做兩件事:觸發間隔setInterval()並將其返回值(ID)作爲參數傳入。該參數值將在其呼叫時間內(可能在未來幾分鐘)內部功能可用。現在回調post()實際上可以停止時間間隔。

作爲練習你;)

  • 修改Ajax調用,使其停止對請求錯誤或超時間隔,太。目前,如果回調從未運行(並且只在成功時運行!),則間隔永遠不會停止。
  • 確保post()不會無意中被觸發兩次。
+0

這是一個認真的答覆,需要一些研究。感謝Tomalak! – FFish 2010-04-12 19:54:04

+0

@FFISH:請注意,這些都沒有經過實際測試,它只是讓你開始。我更徹底地解釋的東西被稱爲封閉,順便說一句。你會發現很多關於JavaScript閉包的東西,以及它們在互聯網上異步JS編程中的重要性。 – Tomalak 2010-04-12 20:30:44

+0

我被你的線卡住了「爲了這個工作,你的圖像處理腳本必須留下一些當然的進展證據。」 我嘗試了與循環示例的會話(也嘗試用sleep()來模擬處理),但腳本立即執行。爲什麼我需要2個PHP腳本? – FFish 2010-04-12 22:52:19

4

感謝Tomalak我終於把東西放在一起,工作。 因爲我在處理批處理時實際上並未在服務器上寫入映像文件,所以我在progress.php腳本中編寫了一個日誌文件。

我想知道這是否是這樣做的最好方法。我想避免寫入文件並嘗試使用PHP的$ _session,但似乎無法逐步讀取它。 這是可能的$ _session?

HTML:

<a class="download" href="#">request download</a> 
<p class="message"></p> 

JS:

$('a.download').click(function() { 
    var queryData = {images : ["001.jpg", "002.jpg", "003.jpg"]}; 

    var progressCheck = function() { 
     $.get("progress.php", 
      function(data) { 
       $("p.message").html(data); 
      } 
     ); 
    }; 

    $.post('proccess.php', queryData, 
     function(intvalId) { 
      return function(data) { 
       $("p.message").html(data); 
       clearInterval(intvalId); 
      } 
     } (setInterval(progressCheck, 1000)) 
    ); 

    return false; 
}); 

process.php:

$arr = $_POST['images']; 
$arr_cnt = count($arr); 
$filename = "log.txt"; 

$i = 1; 
foreach ($arr as $val) { 
    $content = "processing $val ($i/$arr_cnt)"; 

    $handle = fopen($filename, 'w'); 
    fwrite($handle, $content); 
    fclose($handle); 

    $i++; 
    sleep(3); // to mimic image processing 
} 

echo "<a href='#'>download zip</a>"; 

progress.php:

$filename = "log.txt"; 
$handle = fopen($filename, "r"); 
$contents = fread($handle, filesize($filename)); 
fclose($handle); 

echo $contents;