javascript XMLHttpRequest 级别 2 - 确定上传是否完成

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15418608/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-27 00:43:16  来源:igfitidea点击:

XMLHttpRequest Level 2 - Determinate if upload finished

javascriptajaxuploadxmlhttprequest

提问by ninov

I am using ajax for file uploads. After the file is uploaded, php should check it (mime, size, virus (clamscan) and more) - this takes some seconds for larger files. While the file is uploading, a HTML5 <progress>is filling, when the file is ready and PHP starts checking, the progress should switch to indeterminate. I thought of to ways to do this (which both do notwork):

我正在使用 ajax 进行文件上传。文件上传后,php 应该检查它(mime、大小、病毒(clamscan)等) - 对于较大的文件,这需要几秒钟。当文件上传时,HTML5<progress>正在填充,当文件准备好并且 PHP 开始检查时,进度应该切换到不确定。我认为对的方式来做到这一点(这两者做工作):

Checking upload.onload event

检查 upload.onload 事件

xhr.upload.addEventListener("load", function (e) {
    $("#uploadprogress").attr("value", false);
    $("#uploadprogress").attr("max", false);
    $("#progress").text("Checking file...");
});

This doesn't work, because the onload-event firest when the request is ready, not when upload is ready.

这不起作用,因为onload-event 在请求准备好时触发,而不是在上传准备好时触发。

Checking if upload progress percentage = 100%

检查上传进度百分比是否 = 100%

xhr.upload.addEventListener("progress", function (e) {
    if (e.lengthComputable && e) {
        p = (e.loaded / e.total);
        if (p==1) {
            $("#uploadprogress").attr("value", false);
            $("#uploadprogress").attr("max", false);
            $("#progress").text("Checking file...");
        } else {
            var percent = Math.ceil(p * 1000) / 10;
            $("#uploadprogress").val(e.loaded);
            $("#uploadprogress").attr("max", e.total);
            $("#progress").text("Uploading... " + percent + "%");
        }
   }
}
});

This does not work, because the upload percentage sometimes stops at approx. 97%, despite the upload is finished and PHP starts handling the files

这不起作用,因为上传百分比有时会停止在大约。97%,尽管上传完成并且 PHP 开始处理文件

Is there another possibility checking this?

还有另一种可能性检查这个吗?

回答by zertosh

The event you want to listen to is readystatechangeon the XHR object (not on XHR.upload). readyStateis 4when the upload has finished sending andthe server closes the connection. loadend/loadfire when the upload has finished regardless of whether the server closes the connection. Just for reference, here are the events you can listen to and when they fire:

您要侦听的事件readystatechange在 XHR 对象上(而不是在 XHR.upload 上)。readyState4当上载完成发送,并在服务器关闭连接loadend/load在上传完成时触发,无论服务器是否关闭连接。仅供参考,以下是您可以收听的事件以及它们何时触发:

    var xhr = new XMLHttpRequest();

    // ...
    // do stuff with xhr
    // ...

    xhr.upload.addEventListener('loadstart', function(e) {
      // When the request starts.
    });
    xhr.upload.addEventListener('progress', function(e) {
      // While sending and loading data.
    });
    xhr.upload.addEventListener('load', function(e) {
      // When the request has *successfully* completed.
      // Even if the server hasn't responded that it finished.
    });
    xhr.upload.addEventListener('loadend', function(e) {
      // When the request has completed (either in success or failure).
      // Just like 'load', even if the server hasn't 
      // responded that it finished processing the request.
    });
    xhr.upload.addEventListener('error', function(e) {
      // When the request has failed.
    });
    xhr.upload.addEventListener('abort', function(e) {
      // When the request has been aborted. 
      // For instance, by invoking the abort() method.
    });
    xhr.upload.addEventListener('timeout', function(e) {
      // When the author specified timeout has passed 
      // before the request could complete.
    });

    // notice that the event handler is on xhr and not xhr.upload
    xhr.addEventListener('readystatechange', function(e) {
      if( this.readyState === 4 ) {
        // the transfer has completed and the server closed the connection.
      }
    });

回答by luigifab

Based on https://bugzilla.mozilla.org/show_bug.cgi?id=637002.

基于https://bugzilla.mozilla.org/show_bug.cgi?id=637002

Let's go for a complete working example...

让我们来看一个完整的工作示例......

// YOUR (SIMPLE) JAVASCRIPT FILE
var form = new FormData(), xhr = new XMLHttpRequest();
form.append('inputname', YOURFILE);

xhr.open('POST', 'http://oneserver/onephpfile', true);
xhr.setRequestHeader('X-CSRF-Token', 'somestring');
xhr.onreadystatechange = function () {
    if ((xhr.readyState === 4) && (xhr.status === 200))
        // do other thing with xhr.responseText.trim()
};

xhr.upload.addEventListener('loadstart', showProgressBarFunction, false);
xhr.upload.addEventListener('progress',  updateProgressBarFunction, false);
xhr.upload.addEventListener('load',      updateProgressBarFunction, false);
xhr.send(form);

// YOUR FIRST (SIMPLE) PHP FILE
header('Content-Type: text/plain; charset=utf-8');
header('Cache-Control: no-cache, must-revalidate');

sleep(20);
echo 'file processing ended';

With this first PHP file, you will see: 10%... 50%... 75%... 'do other thing'with Firefox (4/10/28/32) and IE (10/11). Howeveryou we will see: 10%... 50%... 75%... 100%... 'do other thing'with Chrome/Chromium (33/37) and Opera (24).

使用第一个 PHP 文件,您将看到:10%... 50%... 75%...使用 Firefox (4/10/28/32) 和 IE (10/11) “做其他事情”但是你会看到:10%... 50%... 75%... 100%...用 Chrome/Chromium (33/37) 和 Opera (24) '做其他事情'

// YOUR SECOND (SIMPLE) PHP FILE
header('Content-Encoding: chunked', true);
header('Content-Type: text/plain; charset=utf-8');
header('Cache-Control: no-cache, must-revalidate');
ini_set('output_buffering', false);
ini_set('implicit_flush', true);
ob_implicit_flush(true);
for ($i = 0; $i < ob_get_level(); $i++)
    ob_end_clean();
echo ' ';

sleep(20);
echo 'file processing ended';

With this second PHP file, you will see: 10%... 50%... 75%... 100%... 'do other thing'with Chrome/Chromium (33/37/53), Opera (24/42), Firefox (4/10/28/32/45), IE (10/11) and Edge (14)!

使用第二个 PHP 文件,您将看到:10%... 50%... 75%... 100%... 'do other thing'with Chrome/Chromium (33/37/53), Opera (24 /42)、Firefox (4/10/28/32/45)、IE (10/11) 和 Edge (14)!

回答by shadowstorm

This is a relatively known downfall of the hTML5 spec, when they could have easily extended it to add information such as timeRemaining and transferSpeed.

这是 hTML5 规范的一个相对众所周知的垮台,当时他们可以轻松地扩展它以添加诸如 timeRemaining 和 transferSpeed 之类的信息。

Have you considered using math.roundinstead of math.ceilfor var percentso that you are baking in a bit of fuzziness that would help get around a few % points being off?

你有没有考虑过使用math.round而不是math.ceilfor 来var percent让你在一些模糊的情况下烘焙,这将有助于解决几个百分点的问题?

You should also add another listener for loadComplete, if you are getting the UI stuck at <100% even though it is complete on the backend:

您还应该为 loadComplete 添加另一个侦听器,如果您的 UI 卡在 <100%,即使它在后端已完成:

//only fires once
xhr.addEventListener('loadend', uploadComplete, false);
function uploadComplete(event) {
    console.log('rejoice...for I have completed');
    //do stuff
}

回答by aIKid

Check the readyState, if(readyState==4) {//it has finished, put code here}

检查就绪状态, if(readyState==4) {//it has finished, put code here}