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++;
}
?>

 

效果图:

总感觉里面有很多代码是多余的,大家自己剪掉吧,各自可以进行具体测试。原理就是刷缓冲区,其它语言应该也差不多吧,本人水平只能理解到这个了,如果大家知道的是其它技术的话,一起讨论下,别私藏啊,回复告诉我哦。

 

posted on 2012-12-27 10:36  幻林的地盘  阅读(3316)  评论(12编辑  收藏  举报

导航