posts - 36, comments - 419, trackbacks - 0, articles - 0
  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

 

ajax应用越来越多,大部分ajax处理都是在前台显示1个"loading...",然后把数据提交给服务器进行处理,处理完毕后显示"处理完毕"。
我们能否让ajax更加友好点,实时显示服务器处理的进度了?这在一些长时间的请求中尤其重要,比如上传文件、发送邮件、批量处理数据。
答案当然是可以的,不然就不会写这个了,对吧,^_^。

      ajax应用越来越多,大部分ajax处理都是在前台显示1个"loading...",然后把数据提交给服务器进行处理,处理完毕后显示"处理完毕"。我们能否让ajax更加友好点,实时显示服务器处理的进度了?这在一些长时间的请求中尤其重要,比如上传文件、发送邮件、批量处理数据。答案当然是可以的,不然就不会写这个了,对吧,^_^。

 

 

存在的问题:    

   要解决实现上面的功能,需要解决下面几个问题:

   1. 服务器如何在处理一部分数据后传递部分response到浏览器。

   2、浏览器如何能处理服务器传递过来部分数据,并保持http连接直到处理完全完毕。

 

   要解决第1个问题,使用flush让response分块进行呈现就可以了,具体请参考我另一遍随笔"flush让页面分块,逐步呈现";

   第2个问题,则需要用到XMLHttpRequest的readyState状态,w3c对 readyState 定义如下几个值:

  UNSENT = 0; // 没有发送请求

  OPENED = 1;    // 已经打开http连接

  HEADERS_RECEIVED = 2; // 接收到response header

  LOADING = 3;          // 真正接收response body   

  DONE = 4;             // 请求接收完毕

   相信状态4大家是天天在用,而我们这里需要用到就是状态3。

 

 

实例:  

     废话少说,代码实例比什么文字解释都管用。我们这里假设服务器的1个处理需要6秒种,每秒种处理1条记录,总共处理6条记录,我们需要服务器每处理完1条数据,客户端则显示处理进度(包括文字和进度条)。

 

   服务器端代码(下面JSP代码):

    <%
    // 下面设置Content-Type:application/x-javascript 是为了适应Webkit的浏览器(chrome,safari)
      response.setHeader("Content-Type","application/x-javascript");
      
int count = 6;    //    处理6条数据
      for(int i=0;i<count;i++){
          
// 处理完毕一条,输出结果到客户端
          out.println(i+1);
          out.flush();
          
// 这里假设每条数据处理时间为1秒
          Thread.currentThread().sleep(1000);
      }
   
%>

 

    html代码:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    
<style>
        #divProgress
{width:300px;height:24px;position:relative;}
        #divProgress div
{position:absolute;left:0;top:0;height:24px;}
        #progressBg
{background-color:#B9F8F9;z-index:10;}
        #progressText
{z-index:15;text-align:center;width:100%;}
    
</style>    
</head>
<body>
     
<div id="divProgress">
          
<div id="progressBg"></div>
         
<div id="progressText"></div>
     
</div>
     
<br />
     
<button onclick="send()">提交数据</button>
     
<script>
         
var t = document.getElementById("progressText");
         
var bg = document.getElementById("progressBg");
        
function send(){
            t.innerHTML 
= "loading";
            bg.style.width 
= "0px";
            
            
var xhr = new window.XMLHttpRequest();
            
if(!window.XMLHttpRequest){
                    
try {
                        xhr 
= new window.ActiveXObject("Microsoft.XMLHTTP");
                    } 
catch(e) {}
            }
            xhr.open(
"post","http://localhost:801/ChunkTest/chunk.jsp?count=6");
            
var oldSize=0;
            xhr.onreadystatechange 
= function(){
                
if(xhr.readyState > 2){                 
                  
var tmpText = xhr.responseText.substring(oldSize); 
                  oldSize 
= xhr.responseText.length;
                  
if(tmpText.length > 0 ){
                      
// 设置文本
                      t.innerHTML = tmpText + "/6";
                      
// 设置进度条
                      var width = parseInt(tmpText)/6*300;
                      bg.style.width 
= width+"px";
                    }
                }
                
if(xhr.readyState == 4){ 
                    
// 请求执行完毕
                    t.innerHTML = "执行完毕";
                    bg.style.width 
= "300px";
                }
            }
            xhr.send(
null);
      }
    
</script>
</body>
</html>

 

    运行效果图: 

    

 

缺点:

     看到这里或许你已经蠢蠢欲动,想自己动手试试了。但是注意上面的方法虽好,但也有个缺点,就是浏览器的支持问题。目前IE所有版本的浏览器都不支持 xhr.readyState == 3状态,IE浏览器不支持在response响应完毕前读取responseText属性。  具体可查看MSDN :  XMLHttpRequest Object 

     基于Webkit的浏览器支持的不是很好,需要设置Content-Type:application/x-javascript才行(经测试发现Content-Type:text/html在有些情况下正常,有些情况下又不正常,而用application/x-javascript都正常)。

     看到了缺点后是否又打击了你的积极性了,其实针对IE,我们不需要做太多处理,IE不支持,就不会显示进度,就变成跟传统的ajax请求一样,一直显示1个loading直到请求完毕。我们只需要加1个简单的判断,判断如果是ie则不执行xhr.readyState > 2中的代码,如果不加判断,IE下会报JS错误.

 

DEMO:

   demo服务器不太好,而且在国外,随时可能会点击不了,而且有时候运行效果不是很好,大家知晓下,最好是把代码copy到本地进行测试。

   请使用firefox或chrome查看demo,ie查看的效果跟一般的ajax没什么不一样。

   http://213.186.44.204:8080/ChunkTest/index.html 



[作者]:BearRui(AK-47)
[博客]: http://www.blogjava.net/bearrui/
[声明]:本博所有文章版权归作者所有(除特殊说明以外),转载请注明出处.
英雄,别走啊,帮哥评论下:  

精彩推荐 好文要顶 水平一般 看不懂 还需努力

评论

# re: 让ajax更加友好,实时显示后台处理进度。  回复  更多评论   

2010-06-02 12:32 by thebye85
很不错,谢谢分享

# re: 让ajax更加友好,实时显示后台处理进度。  回复  更多评论   

2010-06-02 14:14 by 菠萝大象
为什么不用jQuery?jQuery的跨浏览器无疑是非常强大的。

# re: 让ajax更加友好,实时显示后台处理进度。  回复  更多评论   

2010-06-02 14:17 by BearRui(AK-47)
@thebye85
谢谢支持

# re: 让ajax更加友好,实时显示后台处理进度。  回复  更多评论   

2010-06-02 14:17 by BearRui(AK-47)
@菠萝大象
jquery并没有这样的功能,jquery的ajax都是在readyState==4后才执行代码

# re: 让ajax更加友好,实时显示后台处理进度。  回复  更多评论   

2010-06-03 11:30 by noname
感谢分享,这种方法适用于时间比较长而且可以预期处理时间的场景,如果时间很短就没有必要。还是很有意思的

# re: 让ajax更加友好,实时显示后台处理进度。  回复  更多评论   

2010-06-03 12:17 by BearRui(AK-47)
@noname
的确是这样,并不是所有情况都适合使用这种方法。

# re: 让ajax更加友好,实时显示后台处理进度。  回复  更多评论   

2010-06-04 10:20 by @beyondwcm
ajax 还可以多次 out.flush();

# re: 让ajax更加友好,实时显示后台处理进度。  回复  更多评论   

2010-06-04 13:10 by 税国政
可惜ie不支持啊

# re: 让ajax更加友好,实时显示后台处理进度。  回复  更多评论   

2010-06-04 13:12 by BearRui(AK-47)
呵呵,是有利有弊的

# re: 让ajax更加友好,实时显示后台处理进度。  回复  更多评论   

2010-06-24 13:31 by pandora jewels
值得一看,都是专业人士啊!

# re: 让ajax更加友好,实时显示后台处理进度。[未登录]  回复  更多评论   

2010-07-13 18:27 by 123
很想知道你在 ie 中 是怎么处理 readstatus > 3 的??应该总有解决的
办法吧??

# re: 让ajax更加友好,实时显示后台处理进度。  回复  更多评论   

2010-07-13 20:31 by BearRui(AK-47)
@123

IE 不支持readstatus ,如果IE要支持这种功能,就需要采用ajax轮询服务器来实现。

# re: 让ajax更加友好,实时显示后台处理进度。[未登录]  回复  更多评论   

2010-07-14 16:20 by 123
换句话说,你的这种实现方式很好,但是 ie 不支持,火狐是可以的,
我测试过了。。那你能不能有其他的方式去实现这种 后台处理进度,然后再前台实现呢?? 比如用jquery,或者 其他的ajax 框架,来实现 这种 处理进度条呢??很期待你的杰作。。如果有,请发我的邮箱:ypcheng@yeah.net,
谢谢!!!

# re: 让ajax更加友好,实时显示后台处理进度。  回复  更多评论   

2010-07-15 13:15 by BearRui(AK-47)
@123
这种我也做过1个,是做数据导入的时候,使用ajax轮询请求服务器上的导入进度,然后再前台显示,看找个时间写出来。

# re: 让ajax更加友好,实时显示后台处理进度。  回复  更多评论   

2012-05-21 13:19 by jidebingfeng
好文章,顶一下!

# re: 让ajax更加友好,实时显示后台处理进度。  回复  更多评论   

2012-05-21 13:19 by jidebingfeng
文章很精彩,推荐一下!

# re: 让ajax更加友好,实时显示后台处理进度。  回复  更多评论   

2014-07-17 17:20 by aliang
jquery 1.5+应该可以实现吧

var orgAjax = jQuery.ajaxSettings.xhr;
jQuery.ajaxSettings.xhr = function () {
var xhr = orgAjax();
xhr.onreadystatechange = function() {
alert(xhr.readyState)
}
return xhr;
};

只有注册用户登录后才能发表评论。


网站导航: