<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    瘋狂

    STANDING ON THE SHOULDERS OF GIANTS
    posts - 481, comments - 486, trackbacks - 0, articles - 1
      BlogJava :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

    提高AJAX客戶端響應(yīng)速度(轉(zhuǎn)載)

    Posted on 2011-02-11 15:23 瘋狂 閱讀(1037) 評論(0)  編輯  收藏 所屬分類: java性能web方法論架構(gòu)
     

    提高AJAX客戶端響應(yīng)速度

    (文:包一磊)

    AJAX的出現(xiàn)極大的改變了Web應(yīng)用客戶端的操作模式,它使的用戶可以在全心工作時不必頻繁的忍受那令人厭惡的頁面刷新。理論上AJAX技術(shù)在很大的程度上可以減少用戶操作的等待時間,同時節(jié)約網(wǎng)絡(luò)上的數(shù)據(jù)流量。而然,實際情況卻并不總是這樣。用戶時常會抱怨用了AJAX的系統(tǒng)響應(yīng)速度反而降低了。

    筆者從事AJAX方面的研發(fā)多年,參與開發(fā)了目前國內(nèi)較為成熟的AJAX平臺-dorado。根據(jù)筆者的經(jīng)驗,導致這種結(jié)果的根本原因并不在AJAX。很多時候系統(tǒng)響應(yīng)速度的降低都是由不夠合理的界面設(shè)計和不夠高效的編程習慣造成的。下面我們就來分析幾個AJAX開發(fā)過程中需要時刻注意的環(huán)節(jié)。

    合理的使用客戶端編程和遠程過程調(diào)用。

    客戶端的編程主要都是基于JavaScript的。而JavaScript是一種解釋型的編程語言,它的運行效率相對于Java等都要稍遜一籌。同時JavaScript又是運行在瀏覽器這樣一個嚴格受限的環(huán)境當中。因此開發(fā)人員對于哪些邏輯可以在客戶端執(zhí)行應(yīng)該有一個清醒的認識。

    在實際的應(yīng)用中究竟應(yīng)該怎樣使用客戶端編程,這依賴于開發(fā)人員的經(jīng)驗判斷。這里很多問題是只可意會的。由于篇幅有限,在這里我們大致歸納出下面這幾個注意事項:

    盡可能避免頻繁的使用遠程過程調(diào)用,例如避免在循環(huán)體中使用遠程過程調(diào)用。

    如果可能的話盡可能使用AJAX方式的遠程過程調(diào)用(異步方式的遠程過程調(diào)用)。

    避免將重量級的數(shù)據(jù)操作放置在客戶端。例如:大批量的數(shù)據(jù)復制操作、需要通過大量的數(shù)據(jù)遍歷完成的計算等。

    改進對DOM對象的操作方式。

    客戶端的編程中,對DOM對象的操作往往是最容易占用CPU時間的。而對于DOM對象的操作,不同的編程方法之間的性能差異又往往是非常大的。

    以下是三段運行結(jié)果完全相同的代碼,它們的作用是在網(wǎng)頁中創(chuàng)建一個10x1000的表格。然而它們的運行速度卻有著天壤之別。

    /* 測試代碼1 - 耗時: 41*/

    var table = document.createElement("TABLE");

    document.body.appendChild(table);

    for(var i = 0; i < 1000; i++){

     var row = table.insertRow(-1);

     for(var j = 0; j < 10; j++){

        var cell = objRow.insertCell(-1);

         cell.innerText = "( " + i + " , " + j + " )";

     }

    }

    /* 測試代碼2 - 耗時: 7.6 */

    var table = document.getElementById("TABLE");

    document.body.appendChild(table);

    var tbody = document.createElement("TBODY");

    table.appendChild(tbody);

    for(var i = 0; i < 1000; i++){

     var row = document.createElement("TR");

     tbody.appendChild(row);

     for(var j = 0; j < 10; j++){

        var cell = document.createElement("TD");

         row.appendChild(cell);

         cell.innerText = "( " + i + " , " + j + " )";

     }

    }

    /* 測試代碼3 - 耗時: 1.26 */

    var tbody = document.createElement("TBODY");

    for(var i = 0; i < 1000; i++){  

     var row = document.createElement("TR");

           for(var j = 0; j < 10; j++){

        var cell = document.createElement("TD");

         cell.innerText = "( " + i + " , " + j + " )";

         row.appendChild(cell);

     }

     tbody.appendChild(row);

    }

    var table = document.getElementById("TABLE");

    table.appendChild(tbody);

    document.body.appendChild(table);

    這里的“測試代碼1”和“測試代碼2”之間的差別在于在創(chuàng)建表格單元時使用了不同的API方法。而“測試代碼2”和“測試代碼3之間的差別在于處理順序的略微不同。

    “測試代碼1”和“測試代碼2”之間如此大的性能差別我們無從分析,目前所知的是insertRowinsertCellDHTML中表格特有的APIcreateElementappendChildW3C DOM的原生API。而前者應(yīng)該是對后者的封裝。不過,我們并不能因此而得出結(jié)論認為DOM的原生API總是優(yōu)于對象特有的API。建議大家在需要頻繁調(diào)用某一API時,對其性能表現(xiàn)做一些基本的測試。

    “測試代碼2”和“測試代碼3”之間的性能差異主要來自于他們的構(gòu)建順序不同。“測試代碼2”的做法是首先創(chuàng)建最外層的<TABLE>對象,然后再在循環(huán)中依次創(chuàng)建<TR><TD>。而“測試代碼3”的做法是首先在內(nèi)存中由內(nèi)到外的構(gòu)建好整個表格,最后再將它添加到網(wǎng)頁中。這樣做的目的是盡可能的減少瀏覽器重新計算頁面布局的次數(shù)。每當我們將一個對象添加到網(wǎng)頁中時,瀏覽器都會嘗試對頁面中的控件的布局進行重新計算。所以,如果我們能夠首先在內(nèi)存中將整個要構(gòu)造的對象全部創(chuàng)建好,然后再一次性的添加到網(wǎng)頁中。那么,瀏覽器將只會做一次布局的重計算。總結(jié)為一句話那就是越晚執(zhí)行appendChild越好。有時為了提高運行效率,我們甚至可以考慮先使用removeChild將已存在的控件從頁面中移除,然后構(gòu)造完成后再重新將其放置回頁面當中。

    提高字符串累加的速度

    在使用AJAX提交信息時,我可能常常需要拼裝一些比較大的字符串通過XmlHttp來完成POST提交。盡管提交這樣大的信息的做法看起來并不優(yōu)雅,但有時我們可能不得不面對這樣的需求。那么JavaScript中對字符串的累加速度如何呢?我們先來做下面的這個實驗。累加一個長度為30000的字符串。

    /* 測試代碼1 - 耗時: 14.325 */

    var str = "";

    for (var i = 0; i < 50000; i++) {

           str += "xxxxxx";

    }

    這段代碼耗時14.325秒,結(jié)果并不理想。現(xiàn)在我們將代碼改為如下的形式:

    /* 測試代碼2 - 耗時: 0.359 */

    var str = "";

    for (var i = 0; i < 100; i++) {

           var sub = "";

           for (var j = 0; j < 500; j++) {

                  sub += "xxxxxx";

           }

           str += sub;

    }

    這段代碼耗時0.359秒!同樣的結(jié)果,我們做的只是首先拼裝一些較小的字符串然后再組裝成更大的字符串。這種做法可以有效的在字符串拼裝的后期減小內(nèi)存復制的數(shù)據(jù)量。知道了這一原理之后我們還可以把上面的代碼進一步拆散以后進行測試。下面的代碼僅耗時0.140秒。

    /* 測試代碼3 - 耗時: 0.140 */

    var str = ""; 

    for (var i1 = 0; i1 < 5; i1++) {

           var str1 = "";

           for (var i2 = 0; i2 < 10; i2++) {

                  var str2 = "";

                  for (var i3 = 0; i3 < 10; i3++) {

                         var str3 = "";

                         for (var i4 = 0; i4 < 10; i4++) {

                                var str4 = "";

                                for (var i5 = 0; i5 < 10; i5++) {

                                       str4 += "xxxxxx";

                                }

                                str3 += str4;

                         }

                         str2 += str3;

                  }

                  str1 += str2;      

           }

           str += str1; 

    }

    不過,上面這種做法也許并不是最好的!如果我們需要提交的信息是XML格式的(其實絕大多數(shù)情況下,我們都可以設(shè)法將要提交的信息組裝成XML格式),我們還能找到更高效更優(yōu)雅的方法利用DOM對象為我們組裝字符串。下面這段代買組裝一個長度為950015的字符串僅須耗時0.890秒。

    /* 利用DOM對象組裝信息 - 耗時: 0.890 */

    var xmlDoc; 

    if (browserType == BROWSER_IE) {

           xmlDoc = new ActiveXObject("Msxml.DOMDocument");

    }

    else {

           xmlDoc = document.createElement("DOM");

    }

    var root = xmlDoc.createElement("root");

    for (var i = 0; i < 50000; i++) {

           var node = xmlDoc.createElement("data");

           if (browserType == BROWSER_IE) {

                  node.text = "xxxxxx";

           }

           else {

                  node.innerText = "xxxxxx";

           }

           root.appendChild(node);

    }

    xmlDoc.appendChild(root);

    var str;

    if (browserType == BROWSER_IE) {

           str = xmlDoc.xml;

    }

    else {

           str = xmlDoc.innerHTML;

    }

    避免DOM對象的內(nèi)存泄漏。

    關(guān)于IEDOM對象的內(nèi)存泄露是一個常常被開發(fā)人員忽略的問題。然而它帶來的后果卻是非常嚴重的!它會導致IE的內(nèi)存占用量持續(xù)上升,并且瀏覽器的整體運行速度明顯下降。對于一些泄露比較嚴重的網(wǎng)頁,甚至只要刷新幾次,運行速度就會降低一倍。

    比較常見的內(nèi)存泄漏的模型有“循環(huán)引用模型”、“閉包函數(shù)模型”和“DOM插入順序模型”,對于前兩種泄漏模型,我們都可以通過在網(wǎng)頁析構(gòu)時解除引用的方式來避免。而對于“DOM插入順序模型”則需要通過改變一些慣有的編程習慣的方式來避免。

    有關(guān)內(nèi)存泄漏的模型的更多介紹可以通過Google很快的查到,本文不做過多的闡述。不過,這里我向您推薦一個可用于查找和分析網(wǎng)頁內(nèi)存泄露的小工具Drip,目前的較新版本是0.5,下載地址是http://outofhanwell.com/ieleak/index.php

    復雜頁面的分段裝載和初始化

    對系統(tǒng)當中某些確實比較復雜而又不便使用IFrame的界面,我們可以對其實施分段裝載。例如對于多頁標簽的界面,我們可以首先下載和初始化多頁標簽的默認頁,然后利用AJAHasynchronous JavaScript and HTML)技術(shù)來異步的裝載其他標簽頁中的內(nèi)容。這樣就能保證界面可以在第一時間首先展現(xiàn)給用戶。把整個復雜界面的裝載過程分散到用戶的操作過程當中。

    利用GZIP壓縮網(wǎng)絡(luò)流量。

    除了上面提到的這些代碼級的改良之外,我們還可以利用GZIP來有效的降低網(wǎng)絡(luò)流量。目前常見的主流瀏覽器已經(jīng)全部支持GZIP算法,我們往往只需要編寫少量的代碼就可以支持GZIP了。例如在J2EE中我們可以在Filter中通過下面的代碼來判斷客戶端瀏覽器是否支持GZIP算法,然后根據(jù)需要利用java.util.zip.GZIPOutputStream來實現(xiàn)GZIP的輸出。

    /* 判斷瀏覽器對GZIP支持方式的代碼 */

    private static String getGZIPEncoding(HttpServletRequest request) {

     String acceptEncoding = request.getHeader("Accept-Encoding");

     if (acceptEncoding == null) return null;

     acceptEncoding = acceptEncoding.toLowerCase();

     if (acceptEncoding.indexOf("x-gzip") >= 0) return "x-gzip";

     if (acceptEncoding.indexOf("gzip") >= 0) return "gzip";

     return null;

    }

    一般而言,GZIP對于HTMLJSP的壓縮比可以達到80%左右,而它造成的服務(wù)端和客戶端的性能損耗幾乎是可以忽略的。結(jié)合其他因素,支持GZIP的網(wǎng)站有可能為我們節(jié)約50%的網(wǎng)絡(luò)流量。因此GZIP的使用可以為那些網(wǎng)絡(luò)環(huán)境不是特別好的應(yīng)用帶來顯著的性能提升。使用Http的監(jiān)視工具Fiddler可以方便的檢測出網(wǎng)頁在使用GZIP前后的通訊數(shù)據(jù)量。Fiddler的下載地址是http://www.fiddlertool.com/fiddler/

    關(guān)于Web應(yīng)用的性能優(yōu)化其實是一個非常大的話題。本文由于篇幅有限,只能涉及其中的幾個細節(jié),并且也無法將這些細節(jié)的優(yōu)化方式全面的展現(xiàn)給大家。期望本文能夠引起大家對Web應(yīng)用尤其是客戶端性能優(yōu)化的充分重視。畢竟服務(wù)端編程技巧已為大家熟知多年,在服務(wù)端挖掘性能的潛力已經(jīng)不大了。而在客戶端的方法改進往往能夠得到令人驚奇的性能提升。

    主站蜘蛛池模板: 免费做爰猛烈吃奶摸视频在线观看| 免费大片av手机看片高清| 中文成人久久久久影院免费观看| 国产一区二区三区免费在线观看 | 青柠影视在线观看免费| 亚洲精品麻豆av| 一级毛片成人免费看a| 亚洲第一福利网站在线观看| 一级毛片正片免费视频手机看| 四虎国产精品免费视| 美女被艹免费视频| 亚洲成a人一区二区三区| 四虎一区二区成人免费影院网址| 亚洲国产精品一区二区九九| 久久久久久噜噜精品免费直播| 亚洲狠狠婷婷综合久久久久 | 亚洲国产精品日韩在线| 91免费播放人人爽人人快乐| 亚洲一区二区三区亚瑟 | 亚洲国产小视频精品久久久三级| 男人和女人高潮免费网站| 青青草原亚洲视频| 免费无码av片在线观看| 亚洲第一永久在线观看| 在线观看av永久免费| 亚洲精品尤物yw在线影院| 久久久久免费视频| 国产免费看JIZZ视频| 亚洲av无码专区首页| 亚洲日韩乱码中文无码蜜桃臀网站| 亚洲最大在线观看| 日本免费一二区在线电影| 五月天婷婷免费视频| 亚洲国产精品自在线一区二区 | 人妻无码中文字幕免费视频蜜桃| 亚洲一本大道无码av天堂| 一区二区三区观看免费中文视频在线播放| 亚洲成年人电影在线观看| 免费在线精品视频| 最好看最新的中文字幕免费| 国产精品xxxx国产喷水亚洲国产精品无码久久一区 |