TA的每日心情 | 开心 2021-3-12 23:18 |
---|
签到天数: 2 天 [LV.1]初来乍到
|
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代码): <%[/code]
//
下面设置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错误.
出处:http://www.blogjava.net/BearRui/
|
|