3

我有一个脚本需要几秒钟的处理时间,最多大约一分钟。该脚本调整图像数组的大小,锐化它们,最后将它们压缩起来供用户下载。

现在我需要一些进度信息。我在想,使用 jQuery 的.post()方法,来自回调函数的数据会逐渐更新,但这似乎不起作用。

在我的示例中,我只是使用循环来模拟我的脚本:

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

循环.php:

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

2 回答 2

5

更新:由于 jQuery Ajax 请求有一个 Promise 接口,因此获取进度信息要容易得多。使用这个答案:

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()不会意外触发两次。
于 2010-04-12T19:39:02.773 回答
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;
});

进程.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>";

进度.php:

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

echo $contents; 
于 2010-04-18T09:33:42.213 回答