2010-04-12 58 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;