B/S架构的进度条原理
这个星期老大问了我两次同样的一个问题,“CRM批量操作能不能做进度条啊?”,‘CRM’是一套B/S架构的系统;第一次我回答了不能,因为我不想做,第二次我回答可以,说强刷缓冲区就可以了,最后老大又问了CRM的老大,那边又说不可以,哎,我就郁闷了,其实只是人家不想做而已啦。
好了,背景就这么多了,记下这是ajax请求的做的一个进度条,先说下原理吧,浏览器发出请求到服务器,这里服务器的处理程序的语言我就用PHP吧,请求到了服务器,程序就进行处理返回字符串。一般情况下批量操作都少不了循环吧,好,PHP一个for里面echo。。echo的,这样每次echo浏览器显示的百分数就叠加一下,这样就像进度条了。但是结果不是想的那么如意,而是把全部的echo拼接起来返回了一个字符串,这是为什么呢?是不是echo太快了帮我拼接起来了呢?来个sleep(2);。不如意,结果还是一样,哎,其实就是缓冲区在作怪嘛,本人水平低,只能责怪缓冲区了,当我们用echo或者print_r()输出的时候,被输出的东西并不是马上到了浏览器的,而是被缓冲区存起来了,除非缓冲区满了或者程序结束了才会输出到浏览器,或者命令它输出,哎呀,来啦来啦,原来可以命令输出,事情就简单了,那就有办法叫它每次echo都向浏览器发送内容了,浏览器只要监听它发送回来的东西就解决了。
这里开始要进入缓冲区讨论了,但是网上很多说没有ob_start()的话,echo都会去浏览器,我试了却不是的,还有很多说用了ob_start()打开,然后ob_end_flush(),就能命令一次发送了,但是我试了之后有时候可以有时候不可以,后来我想想这个太不稳定了吧,不知道是不是版本问题,还是我代码写错了,于是我找到了ob_implicit_flush()这个方法,网上说是强制刷新缓冲区,试了果然每次都可以了,哇,开心啊,解决了,不说废话了,放代码吧。
这是js的代码,发出ajax请求的(看着就头晕是吧):
简单解析下,其中有用到ext js的MessageBox,还有大家不用管gblPageTabObject[gblCurrentTabName].,因为这个系统的多页签,所以才用这个的,当做是一个变量就可以了,
gblPageTabObject[gblCurrentTabName].msgBox = Ext.MessageBox;//定义全局,不然会闪的
gblPageTabObject[gblCurrentTabName].msgv = 0;//返回的进度变量
gblPageTabObject[gblCurrentTabName].count = 20;//进度条的总值,视各自情况而定
//按钮的触发函数(onclick=”gblPageTabObject[gblCurrentTabName].testWin()“),只管这个函数,都面的是被调用
gblPageTabObject[gblCurrentTabName].testWin=function()
{
gblPageTabObject[gblCurrentTabName].msgv = 0;
xmlHttp=GetXmlHttpObject();
if (xmlHttp==null)
{
alert ("Browser does not support HTTP Request");
return;
}
var url="/cust/test/test3.php?count="+gblPageTabObject[gblCurrentTabName].count;
xmlHttp.onreadystatechange=stateChanged;//请求后的监听函数
xmlHttp.open("GET",url,true);
xmlHttp.send(null);
msgBoxShow(gblPageTabObject[gblCurrentTabName].msgv,gblPageTabObject[gblCurrentTabName].count);//显示进度条
}
//监听函数
function stateChanged()
{
//xmlHttp.responseText,返回的结果,大家都知道的
if (xmlHttp.readyState==4 || xmlHttp.readyState=="complete")
{
var obj = xmlHttp.responseText;
alert(obj);
gblPageTabObject[gblCurrentTabName].msgBox.hide();
}
if (xmlHttp.readyState==3)
{
var obj = xmlHttp.responseText;
arr=obj.split("-");
gblPageTabObject[gblCurrentTabName].msgv = arr[arr.length-1];
msgBoxShow(gblPageTabObject[gblCurrentTabName].msgv,gblPageTabObject[gblCurrentTabName].count);
//alert(obj);
}
}
//显示进度条,ext的控件,progress,updateProgress方法
function msgBoxShow(msgv,count){
v = msgv;
gblPageTabObject[gblCurrentTabName].msgBox.progress("请等待", "数据处理进度...'");
gblPageTabObject[gblCurrentTabName].msgBox.updateProgress(v/count,v/count+"已完成");
}
//创建请求对象
function GetXmlHttpObject()
{
var xmlHttp=null;
try
{
// Firefox, Opera 8.0+, Safari
xmlHttp=new XMLHttpRequest();
}
catch (e)
{
// Internet Explorer
try
{
xmlHttp=new ActiveXObject("Msxml2.XMLHTTP");
}
catch (e)
{
xmlHttp=new ActiveXObject("Microsoft.XMLHTTP");
}
}
return xmlHttp;
}
好了,请求发送出去了,到服务器处理了,一下才是关键,原理所在啊,不过只要一点代码
<?php
$result->success='success';
$result->msg='aaa';
$v=0;
ob_implicit_flush();//强制刷新,让服务器向浏览器发送内容
ob_start();
$count = $_GET["count"];
for($i=0;$i<$count;$i++)
{
if($i==$v)
{
//ob_end_clean();
//if($i==2||$i==5)
// sleep(2);
sleep(1);
//echo json_encode($result);
ob_end_clean();
echo '-'.$i;
ob_end_flush();//让服务器向浏览器发送内容,很奇怪这句话有时候没有也可以,不知道是不是我用虚拟机的问题
//ob_end_clean();
ob_start();
}
$v++;
}
?>
效果图:
总感觉里面有很多代码是多余的,大家自己剪掉吧,各自可以进行具体测试。原理就是刷缓冲区,其它语言应该也差不多吧,本人水平只能理解到这个了,如果大家知道的是其它技术的话,一起讨论下,别私藏啊,回复告诉我哦。