关于javascript:如何从XMLHttpRequest获取进度

How to get progress from XMLHttpRequest

是否可以获取XMLHttpRequest的进度(上传的字节数,下载的字节数)?

当用户上传大文件时,这对于显示进度栏很有用。 标准API似乎不支持它,但是也许在任何浏览器中都有一些非标准扩展? 毕竟,这似乎是一个非常明显的功能,因为客户端知道上载/下载了多少字节。

注意:我知道"轮询服务器以获取进度"替代方案(这是我现在正在做的事情)。 这样做的主要问题(除了复杂的服务器端代码)是,通常,在上传大文件时,用户的连接已完全断开,因为大多数ISP的上游情况较差。 因此,发出额外的请求并不像我希望的那样迅速。 我希望有一种方法(可能是非标准的)来获取此信息,而浏览器始终都有。


对于上传的字节,这非常容易。只需监视xhr.upload.onprogress事件。浏览器知道它必须上传的文件的大小以及上传的数据的大小,因此它可以提供进度信息。

对于下载的字节(使用xhr.responseText获取信息时),要困难一些,因为浏览器不知道服务器请求中将发送多少字节。在这种情况下,浏览器唯一知道的就是它接收的字节大小。

有一个解决方案,在服务器脚本上设置Content-Length标头就足够了,以便获得浏览器将要接收的字节的总大小。

有关更多信息,请访问https://developer.mozilla.org/en/Using_XMLHttpRequest。

例:
我的服务器脚本读取一个zip文件(需要5秒钟):

1
2
3
4
5
6
$filesize=filesize('test.zip');

header("Content-Length:" . $filesize); // set header length
// if the headers is not set then the evt.loaded will be 0
readfile('test.zip');
exit 0;

现在,我可以监视服务器脚本的下载过程,因为我知道它的总长度:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
function updateProgress(evt)
{
   if (evt.lengthComputable)
   {  // evt.loaded the bytes the browser received
      // evt.total the total bytes set by the header
      // jQuery UI progress bar to show the progress on screen
     var percentComplete = (evt.loaded / evt.total) * 100;  
     $('#progressbar').progressbar("option","value", percentComplete );
   }
}  
function sendreq(evt)
{  
    var req = new XMLHttpRequest();
    $('#progressbar').progressbar();    
    req.onprogress = updateProgress;
    req.open('GET', 'test.php', true);  
    req.onreadystatechange = function (aEvt) {  
        if (req.readyState == 4)
        {  
             //run any callback here
        }  
    };  
    req.send();
}

Firefox支持XHR下载进度事件。


这里对AJAX模式的进度指示器进行了很好的讨论:

http://ajaxpatterns.org/Progress_Indicator

最有前途的方法之一似乎是向服务器打开第二条通信通道,询问服务器已完成多少传输。


Firefox 3.5将支持上传进度事件


对于上载的总数,似乎没有一种处理方法,但是有些与您要下载的内容相似。一旦readyState为3,您就可以定期查询responseText以下载所有内容,直到一个String为止(这在IE中不起作用),直到所有内容都可用时为止,它将转换到readyState 4。在任何给定时间下载的字节数将等于存储在responseText中的字符串中的总字节数。

对于上载问题的全有或全无的方法,由于您必须传递一个用于上载的字符串(并且可以确定该字符串的总字节数),为readyState 0和1发送的总字节数将为0,而为readyState发送的总数为0 2是您传入的字符串中的总字节。在readyState 3和4中发送和接收的总字节将是原始字符串中的字节总和加上responseText中的总字节。


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
<!DOCTYPE html>
<html>
<body>
<p id="demo">result
</p>
<button type="button" onclick="get_post_ajax();">Change Content</button>
<script type="text/javascript">
    function update_progress(e)
    {
      if (e.lengthComputable)
      {
        var percentage = Math.round((e.loaded/e.total)*100);
        console.log("percent" + percentage + '%' );
      }
      else
      {
        console.log("Unable to compute progress information since the total size is unknown");
      }
    }
    function transfer_complete(e){console.log("The transfer is complete.");}
    function transfer_failed(e){console.log("An error occurred while transferring the file.");}
    function transfer_canceled(e){console.log("The transfer has been canceled by the user.");}
    function get_post_ajax()
    {
        var xhttp;
        if (window.XMLHttpRequest){xhttp = new XMLHttpRequest();}//code for modern browsers}
        else{xhttp = new ActiveXObject("Microsoft.XMLHTTP");}// code for IE6, IE5      
        xhttp.onprogress = update_progress;
        xhttp.addEventListener("load", transfer_complete, false);
        xhttp.addEventListener("error", transfer_failed, false);
        xhttp.addEventListener("abort", transfer_canceled, false);     
        xhttp.onreadystatechange = function()
        {
            if (xhttp.readyState == 4 && xhttp.status == 200)
            {
                document.getElementById("demo").innerHTML = xhttp.responseText;
            }
        };
      xhttp.open("GET","http://it-tu.com/ajax_test.php", true);
      xhttp.send();
    }

</body>
</html>

Result


如果您有权访问apache安装并信任第三方代码,则可以使用apache上传进度模块(如果使用apache,则还有一个nginx上传进度模块)。

否则,您必须编写一个脚本,可以带外使用该脚本来请求文件的状态(例如,检查tmp文件的文件大小)。

我相信在firefox 3中正在进行一些工作,我相信会为浏览器添加上载进度支持,但是这并不会渗透到所有浏览器中,并且会在一段时间内被广泛采用(更可惜的是)。


用纯JavaScript做到这一点的唯一方法是实现某种轮询机制。
您将需要以固定的间隔(例如每5秒发送一次)发送ajax请求,以获取服务器接收的字节数。

一种更有效的方法是使用闪存。 flex组件FileReference定期调度一个'progress'事件,该事件持有已上传的字节数。
如果您需要坚持使用javascript,则可以在actionscript和javascript之间建立桥梁。
好消息是这项工作已经为您完成:)

swfupload

该库允许在Flash进度事件上注册JavaScript处理程序。

该解决方案具有不需要服务器端附加资源的缺点。


推荐阅读

    linux命令暂停下载?

    linux命令暂停下载?,系统,代码,暂停,第一,服务,管理,命令,进程,程序,接线,lin

    linux命令下载工具?

    linux命令下载工具?,工具,网络,代理,代码,简介,位置,系统,第一,下载工具,文

    linux显示错误命令?

    linux显示错误命令?,信息,系统,电脑,状态,时间,环境,命令,搜狐,密码,异常,虚

    linux逐行显示命令?

    linux逐行显示命令?,标准,信息,系统,工作,地址,命令,实时,名称,文件,目录,Lin

    linux命令中添加用户?

    linux命令中添加用户?,系统,密码,软件,用户,命令,信息,目录,用户名,账号,文

    linux显示时间命令?

    linux显示时间命令?,时间,系统,管理,标准,信息,单位,工具,数据,中国,命令,lin

    linux服务器上传命令?

    linux服务器上传命令?,服务,软件,平台,数据,工具,系统,手机,电脑,设备,官网,

    linux下载打包命令行?

    linux下载打包命令行?,软件,系统,名称,工具,官网,文件,命令,目录,下面,表示,l

    linux命令更改用户?

    linux命令更改用户?,系统,密码,管理,用户,命令,环境,工作,地址,电脑,文件,lin

    linux修改用户名命令?

    linux修改用户名命令?,系统,密码,查询系统,代码,数字,用户名,命令,第三,电

    linux命令给用户授权?

    linux命令给用户授权?,系统,数字,管理,权限,命令,密码,工具,时间,软件,信息,l

    linux启动显示命令行?

    linux启动显示命令行?,系统,密码,终端,状态,首页,情况,基础,电脑,信息,工具,l

    linux命令行大全下载?

    linux命令行大全下载?,系统,地址,工作,信息,管理,技术,命令,名家,评论,数据,

    linux上上传命令行?

    linux上上传命令行?,服务,密码,百度,工具,文件,系统,位置,工作,地址,官网,怎

    linux命令创建用户组?

    linux命令创建用户组?,系统,代码,密码,用户组,用户,命令,信息,名称,新增,管

    linux命令下载jdk?

    linux命令下载jdk?,官网,系统,地址,工作,工具,服务,管理,环境,网上,地方,怎样

    linux上上传命令行?

    linux上上传命令行?,服务,密码,百度,工具,文件,系统,位置,工作,地址,官网,怎

    linux中的下载命令行?

    linux中的下载命令行?,软件,系统,网络,电脑,名称,密码,官网,位置,服务,代理,l

    linux命令给用户授权?

    linux命令给用户授权?,系统,数字,管理,权限,命令,密码,工具,时间,软件,信息,l

    linux命令行大全下载?

    linux命令行大全下载?,系统,地址,工作,信息,管理,技术,命令,名家,评论,数据,