3

かなりの数秒の処理、最大で約1分を必要とするスクリプトがあります。スクリプトは、画像の配列のサイズを変更し、画像を鮮明にし、最後にユーザーがダウンロードできるように画像を圧縮します。

今、私はある種の進捗メッセージが必要です。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";
4

2 に答える 2

5

更新: jQuery Ajaxリクエストにはpromiseインターフェースがあるため、進捗情報の取得がはるかに簡単になります。この答えを使用してください:

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


以下の元の回答は古くなっています(元々は2010年のものです)。それでも機能しますが、必要以上に複雑です。参照と比較のためにそのままにしておきます。


サーバーからのある種の進捗情報が必要です。ajaxコールバックはプログレッシブ作業を行わず、リクエストが正常に返された後、1回だけ起動します。

したがって...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)は、1つの引数(間隔ID)を受け取る無名関数です。このIDは、を介して設定された間隔を停止するために必要setInterval()です。幸いなことに、への呼び出しsetInterval()はまさにこのIDを返します。

匿名の外部関数は内部function(data)を返します。これはの実際のコールバックになります$.post()

すぐに外部関数を呼び出し、プロセスで2つのことを実行します。1つは間隔をトリガーしsetInterval()、引数として戻り値(ID)を渡します。この引数値は、呼び出し時に内部関数で使用できるようになります(将来的には数分になる可能性があります)。今のところコールバックpost()は実際に間隔を止めることができます。

あなたのための練習として;)

  • リクエストエラーまたはタイムアウト時にもインターバルを停止するようにajax呼び出しを変更します。現在、コールバックが実行されない場合(そして、成功した場合にのみ実行されます!)、間隔は停止しません。
  • post()を誤って2回トリガーできないようにしてください。
于 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;
});

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; 
于 2010-04-18T09:33:42.213 に答える