【问题标题】:How to get progress from XMLHttpRequest如何从 XMLHttpRequest 获取进度
【发布时间】:2010-09-09 18:29:45
【问题描述】:

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

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

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

【问题讨论】:

    标签: javascript ajax progress-bar


    【解决方案1】:

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

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

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

    欲了解更多信息,请转到https://developer.mozilla.org/en/Using_XMLHttpRequest

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

    $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;
    

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

    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(); 
    }
    

    【讨论】:

    • 值得注意的是,“Content-Length”不是估计的长度,它必须是准确的长度,太短浏览器会中断下载,太长浏览器会假设下载未能完成。
    • @ChrisChilvers 这意味着 PHP 文件可能无法正确计算,对吧?
    • @nicematt 在该示例中,它来自文件会很好,但如果您直接从内存中流式传输 zip,您就不能只是弥补内容长度或估计它。跨度>
    • @TheProHands 当您访问 .php 页面时,服务器会运行 PHP 文件并将其输出发送给您。服务器应该发送输出的长度,而不是 .php 文件。
    • 谁能解释一下"$('#progressbar').progressbar("option", "value", percentComplete);"这行是什么方法?这是调用特定插件吗?这是如何运作的?请让新用户能够理解答案。
    【解决方案2】:

    Firefox 支持XHR download progress events

    编辑 2021-07-08 10:30 PDT

    以上链接已失效。在 Mozilla WebDev 网站上进行搜索发现了以下链接:

    https://developer.mozilla.org/en-US/docs/Web/API/ProgressEvent

    它描述了如何将进度事件与 XMLHttpRequest 一起使用,并提供了一个示例。我已经包含了以下示例:

    var progressBar = document.getElementById("p"),
        client = new XMLHttpRequest()
    client.open("GET", "magical-unicorns")
    client.onprogress = function(pe) {
      if(pe.lengthComputable) {
        progressBar.max = pe.total
        progressBar.value = pe.loaded
      }
    }
    client.onloadend = function(pe) {
      progressBar.value = pe.loaded
    }
    client.send()
    

    我也找到了这个链接,我认为原始链接指向的就是这个链接。

    https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/progress_event

    【讨论】:

    • 链接已损坏,答案未提供任何其他信息。
    • @tforgione 这不是我的答案。但是,我刚刚修复了它。享受吧。
    • 这是一个 JsFiddle,我在其中尝试使用 XMHttpRequest 请求 JQuery 库。 jsfiddle.net/thoakun/7tjnbd8pevent.lengthComputable未定义,无法计算加载进度。
    【解决方案3】:

    最有希望的方法之一似乎是打开第二个通信通道返回服务器,询问它已经完成了多少传输。

    【讨论】:

      【解决方案4】:

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

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

      【讨论】:

        【解决方案5】:

        <!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();
        	}
        </script>
        </body>
        </html>

        【讨论】:

          【解决方案6】:

          如果您有权访问您的 apache 安装并信任第三方代码,则可以使用 apache upload progress module(如果您使用 apache;还有一个 nginx upload progress module)。

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

          我相信在 firefox 3 中正在进行一些工作以向浏览器添加上传进度支持,但这不会进入所有浏览器并在一段时间内被广泛采用(更遗憾的是)。

          【讨论】:

            【解决方案7】:

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

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

            swfupload

            这个库允许在 flash 进度事件上注册一个 javascript 处理程序。

            此解决方案具有不需要服务器端额外资源的巨大优势。

            【讨论】:

              猜你喜欢
              • 2016-08-12
              • 2011-04-28
              • 2011-11-16
              • 1970-01-01
              • 2018-01-23
              • 2014-01-05
              • 1970-01-01
              • 1970-01-01
              • 2014-03-10
              相关资源
              最近更新 更多