简体   繁体   English

jQuery.post动态数据回调函数

[英]jQuery.post dynamic data callback function

I have a script that requires quite a few seconds of processing, up to about minute. 我有一个脚本,需要几秒钟的处理,最多约一分钟。 The script resizes an array of images, sharpens them and finally zips them up for the user to download. 该脚本调整图像数组的大小,锐化它们并最终将它们拉链以供用户下载。

Now I need some sort of progress messages. 现在我需要某种进度信息。 I was thinking that with jQuery's .post() method the data from the callback function would progressively update, but that doesn't seem to work. 我在想,使用jQuery的.post()方法,回调函数中的数据会逐步更新,但这似乎不起作用。

In my example I am just using a loop to simulate my script: 在我的例子中,我只是使用循环来模拟我的脚本:

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

loop.php: loop.php:

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

Update: Getting progress information is a lot easier since jQuery Ajax requests have a promise interface. 更新:获取进度信息要容易得多,因为jQuery Ajax请求具有promise接口。 Use this answer: 使用这个答案:

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


The original answer below is outdated (it is originally from 2010). 以下原始答案已过时(最初来自2010年)。 It still works but is more complicated than it needs to be. 它仍然有效,但比它需要的更复杂。 I'll keep it in place for reference and and comparison. 我会保留它以供参考和比较。


You need some kind of progress info from the server. 您需要来自服务器的某种进度信息。 The ajax callbacks do no progressive work, they fire just once - after the request returned successfully. ajax回调不会执行渐进式工作,只会在请求成功返回后触发一次。

So... in PHP you would need something like this: 所以...在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).'}';

For this to work your image processing script must leave some evidence of its progress of course. 为此,您的图像处理脚本必须留下一些进展的证据。

And in JavaScript something like this: 在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;
  });
});

This part requires some explanation: 这部分需要一些解释:

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

function(intvalId) is an anonymous function that takes one argument - an interval ID. function(intvalId)是一个匿名函数,它接受一个参数 - 一个区间ID。 This ID is necessary to stop an interval that has been set up via setInterval() . 此ID是停止通过setInterval()设置的间隔所必需的。 Luckily, the call to setInterval() returns this very ID. 幸运的是,对setInterval()的调用返回了这个ID。

The anonymous outer function returns an inner function(data) , this one will be the actual callback for $.post() . 匿名外部函数返回一个内部function(data) ,这个function(data)将是$.post()的实际回调function(data)

We call the outer function immediately, doing two things in the process: Triggering off the interval with setInterval() and passing in its return value (the ID) as an argument. 我们立即调用外部函数,在此过程中执行两项操作:使用setInterval()触发间隔并将其返回值(ID)作为参数传递。 This argument value will be available to the inner function at its call time (which may be some minutes in the future). 内部函数在其调用时可以使用此参数值(可能在将来几分钟内)。 The callback for post() now can actually stop the interval. post()的回调现在实际上可以停止间隔。

As an exercise for you ;) 作为锻炼对你;)

  • Modify the ajax call such that it stops the interval on request error or timeout, too. 修改ajax调用,使其在请求错误或超时时停止间隔。 Currently, if the callback is never run (and it runs on success only!), the interval will never stop. 目前,如果回调从未运行(并且仅在成功运行!),则间隔将永远不会停止。
  • Make sure the post() cannot be triggered twice inadvertently. 确保无法无意中触发post()两次。

Thanks to Tomalak I finally put something together that works. 感谢Tomalak,我终于把一些有用的东西放在了一起。 Since I am not actually writing my image files on the server when processing the batch I wrote a log file that I am consulting in the progress.php script. 由于我在处理批处理时实际上并没有在服务器上编写我的图像文件,因此我在progress.php脚本中编写了一个日志文件。

I would like to know if this is the best way of doing this. 我想知道这是否是最好的方法。 I wanted to avoid writing to a file and tried with PHP's $_session but cannot seem to progressively read from it. 我想避免写入文件并尝试使用PHP的$ _session,但似乎无法逐步读取它。 Is this possible with $_session? 这可能是$ _session吗?

HTML: HTML:

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

JS: 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: 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: progress.php:

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

echo $contents; 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM