posts - 36, comments - 419, trackbacks - 0, articles - 0
            BlogJava :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

           

          ajax應(yīng)用越來越多,大部分ajax處理都是在前臺顯示1個"loading...",然后把數(shù)據(jù)提交給服務(wù)器進(jìn)行處理,處理完畢后顯示"處理完畢"。
          我們能否讓ajax更加友好點,實時顯示服務(wù)器處理的進(jìn)度了?這在一些長時間的請求中尤其重要,比如上傳文件、發(fā)送郵件、批量處理數(shù)據(jù)。
          答案當(dāng)然是可以的,不然就不會寫這個了,對吧,^_^。

                ajax應(yīng)用越來越多,大部分ajax處理都是在前臺顯示1個"loading...",然后把數(shù)據(jù)提交給服務(wù)器進(jìn)行處理,處理完畢后顯示"處理完畢"。我們能否讓ajax更加友好點,實時顯示服務(wù)器處理的進(jìn)度了?這在一些長時間的請求中尤其重要,比如上傳文件、發(fā)送郵件、批量處理數(shù)據(jù)。答案當(dāng)然是可以的,不然就不會寫這個了,對吧,^_^。

           

           

          存在的問題:    

             要解決實現(xiàn)上面的功能,需要解決下面幾個問題:

             1. 服務(wù)器如何在處理一部分?jǐn)?shù)據(jù)后傳遞部分response到瀏覽器。

             2、瀏覽器如何能處理服務(wù)器傳遞過來部分?jǐn)?shù)據(jù),并保持http連接直到處理完全完畢。

           

             要解決第1個問題,使用flush讓response分塊進(jìn)行呈現(xiàn)就可以了,具體請參考我另一遍隨筆"flush讓頁面分塊,逐步呈現(xiàn)";

             第2個問題,則需要用到XMLHttpRequest的readyState狀態(tài),w3c對 readyState 定義如下幾個值:

            UNSENT = 0; // 沒有發(fā)送請求

            OPENED = 1;    // 已經(jīng)打開http連接

            HEADERS_RECEIVED = 2; // 接收到response header

            LOADING = 3;          // 真正接收response body   

            DONE = 4;             // 請求接收完畢

             相信狀態(tài)4大家是天天在用,而我們這里需要用到就是狀態(tài)3。

           

           

          實例:  

               廢話少說,代碼實例比什么文字解釋都管用。我們這里假設(shè)服務(wù)器的1個處理需要6秒種,每秒種處理1條記錄,總共處理6條記錄,我們需要服務(wù)器每處理完1條數(shù)據(jù),客戶端則顯示處理進(jìn)度(包括文字和進(jìn)度條)。

           

             服務(wù)器端代碼(下面JSP代碼):

              <%
              // 下面設(shè)置Content-Type:application/x-javascript 是為了適應(yīng)Webkit的瀏覽器(chrome,safari)
                response.setHeader("Content-Type","application/x-javascript");
                
          int count = 6;    //    處理6條數(shù)據(jù)
                for(int i=0;i<count;i++){
                    
          // 處理完畢一條,輸出結(jié)果到客戶端
                    out.println(i+1);
                    out.flush();
                    
          // 這里假設(shè)每條數(shù)據(jù)處理時間為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()">提交數(shù)據(jù)</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 ){
                                
          // 設(shè)置文本
                                t.innerHTML = tmpText + "/6";
                                
          // 設(shè)置進(jìn)度條
                                var width = parseInt(tmpText)/6*300;
                                bg.style.width 
          = width+"px";
                              }
                          }
                          
          if(xhr.readyState == 4){ 
                              
          // 請求執(zhí)行完畢
                              t.innerHTML = "執(zhí)行完畢";
                              bg.style.width 
          = "300px";
                          }
                      }
                      xhr.send(
          null);
                }
              
          </script>
          </body>
          </html>

           

              運行效果圖: 

              

           

          缺點:

               看到這里或許你已經(jīng)蠢蠢欲動,想自己動手試試了。但是注意上面的方法雖好,但也有個缺點,就是瀏覽器的支持問題。目前IE所有版本的瀏覽器都不支持 xhr.readyState == 3狀態(tài),IE瀏覽器不支持在response響應(yīng)完畢前讀取responseText屬性。  具體可查看MSDN :  XMLHttpRequest Object 

               基于Webkit的瀏覽器支持的不是很好,需要設(shè)置Content-Type:application/x-javascript才行(經(jīng)測試發(fā)現(xiàn)Content-Type:text/html在有些情況下正常,有些情況下又不正常,而用application/x-javascript都正常)。

               看到了缺點后是否又打擊了你的積極性了,其實針對IE,我們不需要做太多處理,IE不支持,就不會顯示進(jìn)度,就變成跟傳統(tǒng)的ajax請求一樣,一直顯示1個loading直到請求完畢。我們只需要加1個簡單的判斷,判斷如果是ie則不執(zhí)行xhr.readyState > 2中的代碼,如果不加判斷,IE下會報JS錯誤.

           

          DEMO:

             demo服務(wù)器不太好,而且在國外,隨時可能會點擊不了,而且有時候運行效果不是很好,大家知曉下,最好是把代碼copy到本地進(jìn)行測試。

             請使用firefox或chrome查看demo,ie查看的效果跟一般的ajax沒什么不一樣。

             http://213.186.44.204:8080/ChunkTest/index.html 



          [作者]:BearRui(AK-47)
          [博客]: http://www.aygfsteel.com/bearrui/
          [聲明]:本博所有文章版權(quán)歸作者所有(除特殊說明以外),轉(zhuǎn)載請注明出處.
          英雄,別走啊,幫哥評論下:  

          精彩推薦 好文要頂 水平一般 看不懂 還需努力

          評論

          # re: 讓ajax更加友好,實時顯示后臺處理進(jìn)度。  回復(fù)  更多評論   

          2010-06-02 12:32 by thebye85
          很不錯,謝謝分享

          # re: 讓ajax更加友好,實時顯示后臺處理進(jìn)度。  回復(fù)  更多評論   

          2010-06-02 14:14 by 菠蘿大象
          為什么不用jQuery?jQuery的跨瀏覽器無疑是非常強大的。

          # re: 讓ajax更加友好,實時顯示后臺處理進(jìn)度。  回復(fù)  更多評論   

          2010-06-02 14:17 by BearRui(AK-47)
          @thebye85
          謝謝支持

          # re: 讓ajax更加友好,實時顯示后臺處理進(jìn)度。  回復(fù)  更多評論   

          2010-06-02 14:17 by BearRui(AK-47)
          @菠蘿大象
          jquery并沒有這樣的功能,jquery的ajax都是在readyState==4后才執(zhí)行代碼

          # re: 讓ajax更加友好,實時顯示后臺處理進(jìn)度。  回復(fù)  更多評論   

          2010-06-03 11:30 by noname
          感謝分享,這種方法適用于時間比較長而且可以預(yù)期處理時間的場景,如果時間很短就沒有必要。還是很有意思的

          # re: 讓ajax更加友好,實時顯示后臺處理進(jìn)度。  回復(fù)  更多評論   

          2010-06-03 12:17 by BearRui(AK-47)
          @noname
          的確是這樣,并不是所有情況都適合使用這種方法。

          # re: 讓ajax更加友好,實時顯示后臺處理進(jìn)度。  回復(fù)  更多評論   

          2010-06-04 10:20 by @beyondwcm
          ajax 還可以多次 out.flush();

          # re: 讓ajax更加友好,實時顯示后臺處理進(jìn)度。  回復(fù)  更多評論   

          2010-06-04 13:10 by 稅國政
          可惜ie不支持啊

          # re: 讓ajax更加友好,實時顯示后臺處理進(jìn)度。  回復(fù)  更多評論   

          2010-06-04 13:12 by BearRui(AK-47)
          呵呵,是有利有弊的

          # re: 讓ajax更加友好,實時顯示后臺處理進(jìn)度。  回復(fù)  更多評論   

          2010-06-24 13:31 by pandora jewels
          值得一看,都是專業(yè)人士啊!

          # re: 讓ajax更加友好,實時顯示后臺處理進(jìn)度。[未登錄]  回復(fù)  更多評論   

          2010-07-13 18:27 by 123
          很想知道你在 ie 中 是怎么處理 readstatus > 3 的??應(yīng)該總有解決的
          辦法吧??

          # re: 讓ajax更加友好,實時顯示后臺處理進(jìn)度。  回復(fù)  更多評論   

          2010-07-13 20:31 by BearRui(AK-47)
          @123

          IE 不支持readstatus ,如果IE要支持這種功能,就需要采用ajax輪詢服務(wù)器來實現(xiàn)。

          # re: 讓ajax更加友好,實時顯示后臺處理進(jìn)度。[未登錄]  回復(fù)  更多評論   

          2010-07-14 16:20 by 123
          換句話說,你的這種實現(xiàn)方式很好,但是 ie 不支持,火狐是可以的,
          我測試過了。。那你能不能有其他的方式去實現(xiàn)這種 后臺處理進(jìn)度,然后再前臺實現(xiàn)呢?? 比如用jquery,或者 其他的ajax 框架,來實現(xiàn) 這種 處理進(jìn)度條呢??很期待你的杰作。。如果有,請發(fā)我的郵箱:ypcheng@yeah.net,
          謝謝!!!

          # re: 讓ajax更加友好,實時顯示后臺處理進(jìn)度。  回復(fù)  更多評論   

          2010-07-15 13:15 by BearRui(AK-47)
          @123
          這種我也做過1個,是做數(shù)據(jù)導(dǎo)入的時候,使用ajax輪詢請求服務(wù)器上的導(dǎo)入進(jìn)度,然后再前臺顯示,看找個時間寫出來。

          # re: 讓ajax更加友好,實時顯示后臺處理進(jìn)度。  回復(fù)  更多評論   

          2012-05-21 13:19 by jidebingfeng
          好文章,頂一下!

          # re: 讓ajax更加友好,實時顯示后臺處理進(jìn)度。  回復(fù)  更多評論   

          2012-05-21 13:19 by jidebingfeng
          文章很精彩,推薦一下!

          # re: 讓ajax更加友好,實時顯示后臺處理進(jìn)度。  回復(fù)  更多評論   

          2014-07-17 17:20 by aliang
          jquery 1.5+應(yīng)該可以實現(xiàn)吧

          var orgAjax = jQuery.ajaxSettings.xhr;
          jQuery.ajaxSettings.xhr = function () {
          var xhr = orgAjax();
          xhr.onreadystatechange = function() {
          alert(xhr.readyState)
          }
          return xhr;
          };
          主站蜘蛛池模板: 岫岩| 通海县| 潮安县| 进贤县| 甘泉县| 淮安市| 南投市| 宿松县| 深圳市| 临西县| 宜都市| 平昌县| 梓潼县| 日喀则市| 车致| 石河子市| 福州市| 鄂托克前旗| 高台县| 连山| 米泉市| 林周县| 宜都市| 绥棱县| 灵武市| 襄樊市| 东宁县| 沐川县| 肥西县| 谢通门县| 南溪县| 清水河县| 泸定县| 龙江县| 四川省| 正安县| 和硕县| 报价| 东海县| 大安市| 鹤壁市|