如何从XMLHttpRequest获得进展

时间:2008-09-16 20:56:34

标签: javascript ajax progress-bar

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

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

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

8 个答案:

答案 0 :(得分:132)

对于上传的字节,这很容易。只需监控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(); 
}

答案 1 :(得分:9)

这里有一个很好的讨论AJAX模式的进度指标:

http://ajaxpatterns.org/Progress_Indicator

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

答案 2 :(得分:9)

答案 3 :(得分:7)

答案 4 :(得分:5)

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

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

答案 5 :(得分:3)



<!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>
&#13;
&#13;
&#13;

Result

答案 6 :(得分:2)

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

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

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

答案 7 :(得分:-7)

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

更有效的方法是使用闪光灯。 flex组件FileReference定期发送一个'progress'事件,其中包含已上载的字节数。 如果你需要坚持使用javascript,那么在actionscript和javascript之间可以使用桥接器。 好消息是这项工作已经为您完成了:)

swfupload

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

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