【问题标题】:upload progress with post processing通过后处理上传进度
【发布时间】:2015-02-25 17:24:30
【问题描述】:

我有一个上传表单,用户可以在其中上传文件。上传完成后,对文件进行后处理,有时上传完成后处理需要 10-15 秒。

上传完成后,进度条为 100%,但如何检测文件何时完成,因此您可以在文件处理时向用户显示“请稍候”标志。用户可能会认为浏览器已冻结 og 崩溃,因为进度条处于 100%,但没有发生任何事情..

首选纯 HTML5+javascript 的客户端解决方案,但不是必须的:)

【问题讨论】:

  • 也许是后期处理的第二个进度条?
  • 如果你想控制上传的各个方面,比如你想知道上传多少,上传多少等等,你可以看看resumablejs.com。这个 js 库甚至允许您恢复上传。这使您可以完全控制上传。但是有一个小问题,您还需要在后端进行一些配置。上传后,您可以使用 ajax 进行轮询或使用 node.js 显示后端发生的实时进度。
  • 如果您使用 PHP 作为服务器脚本,那么最好使用 APC 模块。使用它,您可以异步更新进度。
  • 能否请您将处理部分说得更清楚一些。我没有看到任何代码示例,也无法猜测您是如何处理上传的。

标签: php jquery css html


【解决方案1】:

试试

html

<progress min="0" max="10000"></progress>
<output for="progress"></output>
<output for="progress"></output>
<br />
<table id="results"></table>

js

var len = arr.length // file length
    , start = 0 // update progress
    , outputs = $("output[for=progress]") // notifications
    , progress = $("progress")
    , results = $("#results") // post processing 
    // gif spinner
    , spinner = $("<img />", {
    "src": "data:image/gif;charset=binary;base64,R0lGODlhEAAQAPIAAP///wAAAMLCwkJCQgAAAGJiYoKCgpKSkiH+GkNyZWF0ZWQgd2l0aCBhamF4bG9hZC5pbmZvACH5BAAKAAAAIf8LTkVUU0NBUEUyLjADAQAAACwAAAAAEAAQAAADMwi63P4wyklrE2MIOggZnAdOmGYJRbExwroUmcG2LmDEwnHQLVsYOd2mBzkYDAdKa+dIAAAh+QQACgABACwAAAAAEAAQAAADNAi63P5OjCEgG4QMu7DmikRxQlFUYDEZIGBMRVsaqHwctXXf7WEYB4Ag1xjihkMZsiUkKhIAIfkEAAoAAgAsAAAAABAAEAAAAzYIujIjK8pByJDMlFYvBoVjHA70GU7xSUJhmKtwHPAKzLO9HMaoKwJZ7Rf8AYPDDzKpZBqfvwQAIfkEAAoAAwAsAAAAABAAEAAAAzMIumIlK8oyhpHsnFZfhYumCYUhDAQxRIdhHBGqRoKw0R8DYlJd8z0fMDgsGo/IpHI5TAAAIfkEAAoABAAsAAAAABAAEAAAAzIIunInK0rnZBTwGPNMgQwmdsNgXGJUlIWEuR5oWUIpz8pAEAMe6TwfwyYsGo/IpFKSAAAh+QQACgAFACwAAAAAEAAQAAADMwi6IMKQORfjdOe82p4wGccc4CEuQradylesojEMBgsUc2G7sDX3lQGBMLAJibufbSlKAAAh+QQACgAGACwAAAAAEAAQAAADMgi63P7wCRHZnFVdmgHu2nFwlWCI3WGc3TSWhUFGxTAUkGCbtgENBMJAEJsxgMLWzpEAACH5BAAKAAcALAAAAAAQABAAAAMyCLrc/jDKSatlQtScKdceCAjDII7HcQ4EMTCpyrCuUBjCYRgHVtqlAiB1YhiCnlsRkAAAOwAAAAAAAAAAAA=="
});
// upload file
var request = function () {
    progress.prop("max", len);
    s = setInterval(function () {
        progress.prop("value", ++start);
        outputs.eq(0)
            .text("uploading file...")
    }, 1)
    return $.post("/echo/json/", {
        json: JSON.stringify(arr)
    })
    .then(function (data) {
        clearInterval(s)
        s = null;
        progress.prop("value", len);
        outputs.eq(0)
            .html("upload complete ! <br />processing response, please wait...")
        .next(outputs.eq(1))
        .html(spinner);
        return data
    })
};

request()
.then(function (data) {
    // do post upload processing stuff
    var process = function() {
    var dfd = new $.Deferred();
    // processing...
    t = setTimeout(function () {
        data.forEach(function (res) {
            results.append(
            $("<tr />", {
                "html": $("<td />", {
                    "html": res.value
                })
            }))
        });
        if (results.find("tr").length === len) {
           dfd.resolve("complete !")
        }
    }, 1 + Math.floor(Math.random() * 15000));
        return dfd.promise()
    };
    // do stuff when all post processing complete
    process().then(function(complete) {
       outputs.eq(0).empty()
       .next(outputs.eq(1))
       .html(complete);
       clearTimeout(t);
       t = null;
    })
});

jsfiddle http://jsfiddle.net/guest271314/d2szrs20/

【讨论】:

  • 我正在尝试找出您的代码.. 但不是在 HTTP 请求完成时首先触发 jquery ajax 请求(承诺)上的 .then() 吗?
  • @clarkk 你是对的。第一个 thenrequest 内返回对第二个 then 的响应,其中 process 在第二个 then 内返回一个 promise 。有三个.then 调用; 1)处理文件上传,根据filelength设置progress,返回响应第二个.then; 2) 处理来自$.ajax 的响应,在请求可能延迟 10-15 秒后; 3) 完成progress 处理。在实际 file 上传时,arr.length 将是 files[0].size。包含变量 setTimeout 部分以模拟 OP 中描述的“10-15 秒延迟”。
【解决方案2】:

由于您有进度条来显示表单过程要在处理过程中添加更多细节,您可以添加如下图所示

它将向用户显示您的表单仍在处理中create your custom image here

这可能对用户有所帮助 - 浏览器尚未冻结。

【讨论】:

    【解决方案3】:

    我为此使用了自定义上传小部件。在服务器端,当客户端请求更新时,我会向客户端发送以下信息:接收到的文件百分比加上状态消息。通过消息,我可以提供额外的反馈,例如正在执行后处理的哪个步骤或显示错误。

    【讨论】:

      【解决方案4】:

      我正在使用一个名为 pekeupload 的 jquery 插件 它体积小,易于实现和定制

      http://plugins.jquery.com/pekeUpload/ https://github.com/pekebyte/pekeUpload

      希望对你有帮助

      最好的

      【讨论】:

        【解决方案5】:

        Javascript

        function initialize_progress(element)
        {
            //initializations!
            $(element).hide();
            $(element).find('.progress-bar').prop('style','width: 0');
        }
        
        
        function getProgress(process_id){
            var re=new RegExp(process_id+"=[^;]+", "i") //construct RE to search for target name/value pair
            if (document.cookie.match(re)) //if cookie found
                return document.cookie.match(re)[0].split("=")[1] //return its value
            return null
        }
        
        
        function updateProgress(process_id, element){
        
            var percentage, message, name, failed;
        
        
            $(element).show();
            var myIntervalID = setInterval(function()
            {
                percentage = getProgress(process_id+"_percentage");
                name = getProgress(process_id+"_process_name");
                message = getProgress(process_id+"_message");
                failed = getProgress(process_id+"_process_failed");
        
                if(percentage) $(element).find('.progress-bar').css('width',percentage+'%').html(percentage+"% "+message);
        
            },2000);
        }
        
        //initialize progress  bar
        //initialize_progress(".progress");
        
        $(".upload-button").click(function()
        {
        
        
            //set listener
            updateProgress('upload_the_pix', ".progress")
        
        
            var request = $.get( "http://example.com/?progress", function(data) {
                alert(data);
            })
                .done(function() {
                    alert( "second success" )
                }).fail(function() {
                    alert( "error" );
                }).always(function() {
                    alert( "finished" );
                });
        
        
        });
        

        HTML

         <div class="progress">
                                <div class="progress-bar progress-bar-success progress-bar-striped active" role="progressbar" aria-valuenow="40" aria-valuemin="0" aria-valuemax="100" style="width: 0%">
        
                                </div>
                            </div>
        

        服务器端进程 - 使用 PHP

        class ProcessProgress
        {
            protected static $process_id; //current process_id
            protected static $process_name; //current process name
            protected static $debug_mode = false;
            protected static $process_killed = false;
        
        
            /**
             * Make settings for process setup
             * @param $settings
             * Example:
             * $settings=array(
             *   'process_id'    => 'upload_photos' //must be provided
                 'process_name'  =>'Database Wipe', //tile of this process
               );
             */
            public static function settings($settings)
            {
                # process id must be set
        
                #make array keys properties
                if( is_array($settings) ){
                    foreach($settings as $key => $value){
                        self::$$key = $value;
                    }
                }
        
                if(self::$debug_mode && !self::$process_id) exit('process_id must me provided in settings array');
        
                if(isset($_COOKIE[self::$process_id."_percentage"])){
                    unset($_COOKIE[self::$process_id."_percentage"]);
                    unset($_COOKIE[self::$process_id."_message"]);
                    unset($_COOKIE[self::$process_id."_process_name"]);
                    unset($_COOKIE[self::$process_id."_process_complete"]);
                    unset($_COOKIE[self::$process_id."_process_failed"]);
                    unset($_COOKIE[self::$process_id."_process_killed"]);
                }
            }
        
        
            /**
             * Kill this process
             */
            public static function kill()
            {
                self::$process_killed = true;
            }
        
        
            /**
             * @param $percentage
             * @param $message
             * @param bool $complete
             * @param bool $failed
             * @return bool
             */
            public function setProgress($percentage, $message, $complete=false, $failed=false){
        
                $process_data = array(
                    'percentage'=>$percentage,
                    'message' => $message,
                    'process_id' => self::$process_id,
                    'process_name' => self::$process_name,
                    'process_complete' => $complete,
                    'process_failed' => $failed,
                    'process_killed' => self::$process_killed,
                );
        
        
                setcookie(self::$process_id."_percentage", $percentage, time() + (86400 * 30)); // 86400 = 1 day
                setcookie(self::$process_id."_message", $message, time() + (86400 * 30)); // 86400 = 1 day
                setcookie(self::$process_id."_process_name", self::$process_name, time() + (86400 * 30)); // 86400 = 1 day
                setcookie(self::$process_id."_process_complete", $complete, time() + (86400 * 30)); // 86400 = 1 day
                setcookie(self::$process_id."_process_failed", $failed, time() + (86400 * 30)); // 86400 = 1 day
                setcookie(self::$process_id."_process_killed", self::$process_killed, time() + (86400 * 30)); // 86400 = 1 day
        
        
                //verify
                if(isset($_COOKIE[self::$process_id])) return true;
        
                #delay 1 second
                //sleep(1);
            }
        }
        

        点击按钮时在服务器端的使用 http://example.com/?progress

         if(isset($_GET['progress'])){
        ProcessProgress::settings(array(
            'process_id' => 'upload_the_pix',
            'process_name' => 'Picture Upload',
        ));
        
        ProcessProgress::setProgress(0, 'Initializing');
        
        for($count=0; $count < 10001; $count++){
        
            switch($count){
                case 1000:
                    ProcessProgress::setProgress(10, 'Coping files');
                    break;
        
                case 2000:
                    ProcessProgress::setProgress(20, 'Setting up email');
                    break;
        
                case 3000:
                    ProcessProgress::setProgress(30, 'Looking up things');
                    break;
        
                case 4000:
                    ProcessProgress::setProgress(40, 'Milking your cow');
                    break;
        
                case 5000:
                    ProcessProgress::setProgress(50, 'Syncing contacts');
                    break;
        
        
                case 6000:
                    ProcessProgress::setProgress(60, 'Updating Facebook profile');
                    break;
        
                case 7000:
                    ProcessProgress::setProgress(70, 'Calling your girl friend');
                    break;
        
        
                case 8000:
                    ProcessProgress::setProgress(80, 'Making things up');
                    break;
        
                case 9000:
                    ProcessProgress::setProgress(90, 'Feeding your dogs');
                    break;
        
                case 10000:
                    ProcessProgress::setProgress(100, 'Done. Congrats');
                    break;
            }
        }
        

        }

        【讨论】:

          【解决方案6】:

          无论服务器/客户端技术如何,您都可以朝两个方向发展:

          1。首先是线性处理(这是你目前的方式)

          将服务器上的文件从临时发送回显移动到用户后,例如“文件已成功上传。正在处理...”或仅在 JS 中,您可以在上传完成事件时显示消息而无需来自服务器的任何信息或进行另一个 ajax 调用检查......,真的,有很多类似的方法......重点是上传服务器继续文件处理后(例如刚刚上传的PDF或其他文件的OCR 30页),用户必须等待服务器完成处理. 这很奇怪,因为如果很少有用户同时上传文件,那么所有内容都会同时处理,并且您的服务器将 100% 快速运行......所以这让我想到了

          2。使用作业/消息队列

          文件上传后,将文件作业放入队列中,并通知用户您将在处理完成时向他发送邮件(或任何通知用户的方式)(例如当您将文件上传到 issuu 时)。这种方式处理上传的文件(可能在另一台机器上;))一个接一个地完成,用户不必等待文件处理完成......这是首选方式。

          对于作业/消息队列,您可以使用:

          两者都适用于 Java、.NET、Ruby、Python、PHP、Perl、C/C++、Erlang、Node.js,等等……

          祝你好运:)

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2016-07-05
            • 2010-12-28
            相关资源
            最近更新 更多