[转载]让ajax更加友好,实时显示后台处理进度。

[转载]让ajax更加友好,实时显示后台处理进度。 – BearRui(AK-47) – 博客园.

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代码):

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

html代码:

01 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
02 <html xmlns="http://www.w3.org/1999/xhtml">
03 <head>
04 <style>
05 #divProgress{width:300px;height:24px;position:relative;}
06 #divProgress div{position:absolute;left:0;top:0;height:24px;}
07 #progressBg{background-color:#B9F8F9;z-index:10;}
08 #progressText{z-index:15;text-align:center;width:100%;}
09 </style>
10 </head>
11 <body>
12 <div id="divProgress">
13 <div id="progressBg"></div>
14 <div id="progressText"></div>
15 </div>
16 <br />
17 <button onclick="send()">提交数据</button>
18 <script>
19 var t = document.getElementById("progressText");
20 var bg = document.getElementById("progressBg");
21 function send(){
22 t.innerHTML = "loading...";
23 bg.style.width = "0px";
24
25 var xhr = new window.XMLHttpRequest();
26 if(!window.XMLHttpRequest){
27 try {
28 xhr = new window.ActiveXObject("Microsoft.XMLHTTP");
29 } catch(e) {}
30 }
32 var oldSize=0;
33 xhr.onreadystatechange = function(){
34 if(xhr.readyState > 2){
35 var tmpText = xhr.responseText.substring(oldSize);
36 oldSize = xhr.responseText.length;
37 if(tmpText.length > 0 ){
38 // 设置文本
39 t.innerHTML = tmpText + "/6";
40 // 设置进度条
41 var width = parseInt(tmpText)/6*300;
42 bg.style.width = width+"px";
43 }
44 }
45 if(xhr.readyState == 4){
46 // 请求执行完毕
47 t.innerHTML = "执行完毕";
48 bg.style.width = "300px";
49 }
50 }
51 xhr.send(null);
52 }
53 </script>
54 </body>
55 </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.cnblogs.com/BearsTaR/
[声明]:本博所有文章版权归作者所有(除特殊说明以外),转载请注明出处.
赞(0) 打赏
分享到: 更多 (0)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏