在进度元素上显示 AJAX 上载状态步骤 1 :第 2 步:

2022-08-30 10:48:18

我有一个 AJAX 脚本,用于将文件上传到 PHP 脚本,该脚本可能需要至少 10 秒才能运行。我想为用户显示它的进度。

在执行类中,我有一个随进度更新的属性(在1-100中)和一个方法(其目的应该是显而易见的)。$progressget_progress()

问题是,如何更新前端的元素供用户查看?<progress>

我认为AJAX是解决方案,但我就是无法理解它。我无法到达相同的对象实例。


答案 1

我会把它放在这里作为任何搜索者的参考 - 这完全依赖于任何javascript。

<?php

/**
 * Quick and easy progress script
 * The script will slow iterate through an array and display progress as it goes.
 */

#First progress
$array1  = array(2, 4, 56, 3, 3);
$current = 0;

foreach ($array1 as $element) {
    $current++;
    outputProgress($current, count($array1));
}
echo "<br>";

#Second progress
$array2  = array(2, 4, 66, 54);
$current = 0;

foreach ($array2 as $element) {
    $current++;
    outputProgress($current, count($array2));
}

/**
 * Output span with progress.
 *
 * @param $current integer Current progress out of total
 * @param $total   integer Total steps required to complete
 */
function outputProgress($current, $total) {
    echo "<span style='position: absolute;z-index:$current;background:#FFF;'>" . round($current / $total * 100) . "% </span>";
    myFlush();
    sleep(1);
}

/**
 * Flush output buffer
 */
function myFlush() {
    echo(str_repeat(' ', 256));
    if (@ob_get_contents()) {
        @ob_end_flush();
    }
    flush();
}

?>

答案 2

如果你的任务是上传一个巨大的数据集或在服务器上处理它,在更新到服务器的进度时,你应该考虑使用某种作业架构,在那里你启动作业并使用服务器上运行的其他脚本来完成它(例如缩放/处理图像等)。在这种情况下,您一次只做一件事,从而形成一个任务管道,其中有输入和最终处理的输出。

在管道的每个步骤中,任务的状态都在数据库中更新,然后可以通过现在存在的任何服务器推送机制将其发送给用户。运行处理上载和更新的单个脚本会给服务器带来负载,也会限制您(如果浏览器关闭怎么办,如果发生其他错误怎么办)。将流程划分为多个步骤后,您可以从上次成功时恢复失败的任务。

有很多方法可以做到这一点。但整个流程流程如下所示

enter image description here

以下方法是我为个人项目所做的,此脚本非常适合将数千张高分辨率图像上传和处理到我的服务器,然后将其缩小为多个版本并上传到amazon s3,同时识别其中的对象。(我的原始代码是用python编写的)

步骤 1 :

启动传输或任务

首先上传您的内容,然后通过简单的 POST 请求立即返回此交易的交易 ID 或 uuid。如果要在任务中执行多个文件或多个操作,则可能还需要在此步骤中处理该逻辑

第 2 步:

完成工作并返回进度。

一旦你弄清楚了交易是如何发生的,你就可以使用任何服务器端推送技术来发送更新数据包。我会选择WebSocket或Server Sent Events,无论哪个适用,都可以在不受支持的浏览器上回退到Long Polling。一个简单的 SSE 方法将如下所示。

function TrackProgress(upload_id){

    var progress = document.getElementById(upload_id);
    var source = new EventSource('/status/task/' + upload_id );

    source.onmessage = function (event) {
        var data = getData(event); // your custom method to get data, i am just using json here
        progress.setAttribute('value', data.filesDone );
        progress.setAttribute('max', data.filesTotal );
        progress.setAttribute('min', 0);
    };
}

request.post("/me/photos",{
    files: files
}).then(function(data){
     return data.upload_id;
}).then(TrackProgress);

在服务器端,您需要创建一些跟踪任务的东西,一个简单的Jobs架构,其中包含发送到db的job_id和进度就足够了。我会把作业调度留给你和路由,但之后的概念代码(对于最简单的SSE,这将足以满足上述代码)如下。

<?php
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
/* Other code to take care of how do you find how many files are left 
   this is really not required */
function sendStatusViaSSE($task_id){
    $status = getStatus($task_id);
    $json_payload = array('filesDone' => $status.files_done,
                          'filesTotal' => $status.files_total);
    echo 'data: ' . json_encode( $json_payload ) . '\n\n';
    ob_flush();
    flush();

    // End of the game
    if( $status.done ){
        die();
    }

}

while( True ){
     sendStatusViaSSE( $request.$task_id );
     sleep(4);
}

?>

可以在此处找到有关SSE的好教程 http://html5doctor.com/server-sent-events/

您可以阅读有关从服务器推送更新的更多信息,此问题从服务器推送更新

以上是一个概念性的解释,还有其他方法可以实现这一点,但这是我的情况下处理相当艰巨任务的解决方案。


推荐