如何从 XMLHttpRequest 获取进度

IT技术 javascript ajax progress-bar
2021-01-17 18:30:18

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

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

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

6个回答

对于上传的字节,这很容易。只需监视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(); 
}
@nicematt 在那个例子中,它来自一个文件会很好,但是如果你直接从内存中流式传输 zip,你就不能仅仅组成一个内容长度或估计它。
2021-03-12 18:30:18
@ChrisChilvers 这意味着可能无法正确计算 PHP 文件,对吗?
2021-03-19 18:30:18
@TheProHands 当您访问 .php 页面时,服务器会运行 PHP 文件并将其输出发送给您服务器应该发送输出的长度,而不是 .php 文件。
2021-03-28 18:30:18
有人可以解释一下 "$('#progressbar').progressbar( "option", "value", percentComplete );" 方法?这是调用特定的插件吗?这是如何运作的?请让新用户可以理解答案。
2021-04-06 18:30:18
值得注意的是,“Content-Length”不是估计的长度,它必须是准确的长度,太短浏览器会切断下载,太长浏览器会认为下载失败。
2021-04-10 18:30:18

Firefox 支持XHR 下载进度事件

编辑 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 这不是我的答案。但是,我只是修复了它。享受。
2021-03-11 18:30:18
这是一个 JsFiddle,我尝试在其中使用 XMHttpRequest 请求 JQuery 库。jsfiddle.net/thoakun/7tjnbd8pevent.lengthComputable未定义,所以我无法计算加载进度。
2021-04-04 18:30:18
链接已损坏,并且 answer 不提供任何其他信息。
2021-04-08 18:30:18

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

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

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

<!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>

结果