這個星期老大問了我兩次同樣的一個問題,“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++;
}
?>
效果圖:
總感覺里面有很多代碼是多余的,大家自己剪掉吧,各自可以進行具體測試。原理就是刷緩沖區,其它語言應該也差不多吧,本人水平只能理解到這個了,如果大家知道的是其它技術的話,一起討論下,別私藏啊,回復告訴我哦。