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

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

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

    Terry.Li-彬

    虛其心,可解天下之問;專其心,可治天下之學(xué);靜其心,可悟天下之理;恒其心,可成天下之業(yè)。

      BlogJava :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
      143 隨筆 :: 344 文章 :: 130 評論 :: 0 Trackbacks

    Ajax 和 XML: 五種 Ajax 反模式

    避免常見的 Ajax 代碼陷阱

    developerWorks
    文檔選項(xiàng)
    將此頁作為電子郵件發(fā)送

    將此頁作為電子郵件發(fā)送

    未顯示需要 JavaScript 的文檔選項(xiàng)

    討論



    級別: 中級

    Jack D Herrington (jherr@pobox.com), 高級軟件工程師, Leverage Software Inc.

    2007 年 4 月 20 日

    通過理解錯誤的編碼方式,可以更好地了解如何正確地進(jìn)行編碼。當(dāng)然,編寫 Asynchronous JavaScript™ + XML(Ajax)有正確的方法,也有錯誤的方法。本文將討論一些需要避免的常見編碼實(shí)踐。

    如果人們在第一次就能夠?qū)⑺惺虑槿孔鰧Γ敲催@個世界將變得完全不同。Ajax 也是如此。我做了大量的工作以支持 Ajax 開發(fā)人員(包括我自己),包括編碼、撰寫文章和演講。通過這些工作,我學(xué)到了很多關(guān)于正確和錯誤編寫 Ajax 的知識。在我的上一篇文章 “五種常見 Ajax 模式:可立即使用這些非常有用的 Ajax 設(shè)計(jì)模式” 中,我介紹了五種用于正確編寫 Ajax 應(yīng)用程序的模式。在這篇文章中,我將介紹 Ajax 代碼中常見的五種反模式。

    請?jiān)L問 Ajax 技術(shù)資源中心,這是有關(guān) Ajax 編程模型信息的一站式中心,包括很多文檔、教程、論壇、blog、wiki 和新聞。任何 Ajax 的新信息都能在這里找到。

    您可能會問,什么是反模式(anti-pattern)反模式 就是頻繁出現(xiàn)的應(yīng)用程序設(shè)計(jì)缺陷,已經(jīng)成為所有人都應(yīng)該注意的問題。我在這里將從較高的層次進(jìn)行討論,而不涉及語法錯誤和鏈接問題。

    大多數(shù)開發(fā)人員聽說過關(guān)于反模式的一個很好的例子:結(jié)構(gòu)化查詢語言(Structured Query Language,SQL)的錯誤使用導(dǎo)致 Web 站點(diǎn)受到 SQL 注入攻擊。這種反模式使得公司損失慘重,并暴露了客戶記錄,而且不幸的是沒有一種編程語言可以幸免。因此,我們有必要了解這種模式發(fā)生的原理和原因,以及如何避免。

    Ajax 反模式也是如此。我并不是說它們將造成公司損失數(shù)十億的收入,但是它們可以搞垮服務(wù)器或者提供糟糕的用戶體驗(yàn),這種代價不僅昂貴,而且令人沮喪。

    如果理解了發(fā)生錯誤的內(nèi)容,您將學(xué)到很多知識。很多時候,人們僅僅把 Ajax 看作是一種在加載頁面后從服務(wù)器取回 XML 的方式。這種觀點(diǎn)非常狹隘,并且如果被錯誤使用,將引發(fā)應(yīng)用程序的性能問題。在本文中,我將解釋這種觀點(diǎn)之所以錯誤的原因,以及如何修復(fù)這種錯誤。

    在沒有必要的時候輪詢計(jì)時器

    我見到的很多 Ajax 問題都和濫用 JavaScript 語言內(nèi)置的計(jì)時器功能有關(guān)。其中的關(guān)鍵方法是 window.setInterval()。只要看到這種方法,就需要稍微提高警惕;為什么要使用一個計(jì)時器呢?當(dāng)然,計(jì)時器有其用途 —— 比如,動畫。

    window.setInterval() 方法告訴頁面以特定的時間間隔回調(diào)某個函數(shù)(比如每秒)。大多數(shù)瀏覽器對使用這些計(jì)時器總是說得多,做得少,主要是因?yàn)?JavaScript 語言是單線程的語言。如果您要求的時間間隔為 1 秒,那么獲得的回調(diào)時間間隔可能是 1 秒、1.2 秒、9 秒或任何其他時間。

    絕對不需要使用計(jì)時器的一種情況就是等待 Ajax 請求的完成。以 清單 1 為例。


    清單 1. Antipat1a_polling.html
                            <html><script>
                            var req = null;
                            function loadUrl( url ) {
                            if(window.XMLHttpRequest) {
                            try { req = new XMLHttpRequest();
                            } catch(e) { req = false; }
                            } else if(window.ActiveXObject) {
                            try { req = new ActiveXObject('Msxml2.XMLHTTP');
                            } catch(e) {
                            try { req = new ActiveXObject('Microsoft.XMLHTTP');
                            } catch(e) { req = false; }
                            } }
                            if(req) {
                            req.open('GET', url, true);
                            req.send('');
                            }
                            }
                            window.setInterval( function watchReq() {
                            if ( req != null && req.readyState == 4 && req.status == 200 ) {
                            var dobj = document.getElementById( 'htmlDiv' );
                            dobj.innerHTML = req.responseText;
                            req = null;
                            }
                            }, 1000 );
                            var url = window.location.toString();
                            url = url.replace( /antipat1a_polling.html/, 'antipat1_content.html' );
                            loadUrl( url );
                            </script><body>
                            Dynamic content is shown between here:<br/>
                            <div id="htmlDiv" style="border:1px solid black;padding:10px;">
                            </div>And here.</body></html>
                            

    要查看真實(shí)環(huán)境的演示,請查看這個在線版本 在新窗口中打開鏈接以查看 antipat1a_polling.html antipat1a_polling.html.

    在進(jìn)行 setInterval 調(diào)用之前,所有一切看上去都工作得不錯。這個調(diào)用將設(shè)置監(jiān)視請求狀態(tài)的計(jì)時器,然后使用下載的資源設(shè)置頁面內(nèi)容。

    我將展示一個更好的解決方案,用來計(jì)算出什么時候請求能夠完成。同時,清單 2 展示了頁面正在請求的文件。


    清單 2. Antipat1_content.html
                            <b>Hello there</b>
                            

    要查看真實(shí)環(huán)境的演示,請查看這個在線版本 在新窗口中打開鏈接以查看 antipat1_content.html antipat1_content.html.

    同時 圖 1 顯示了在我的瀏覽器中看到的頁面。


    圖 1. 放置在 HTML 文檔中的內(nèi)容
    放置在 HTML 文檔中的內(nèi)容

    所以,您可能會問自己,“它現(xiàn)在可以工作,不是嗎?如果沒有出現(xiàn)故障的話,為什么要修復(fù)呢?” 實(shí)際上已經(jīng)出現(xiàn)故障了,因?yàn)槌绦蜻\(yùn)行得非常慢。計(jì)時器將時間間隔設(shè)置為 1 秒,隨著時間的流逝,請求完全超過了時間間隔。所以,您將看到頁面首先出現(xiàn)一個空的框,然后再等待一秒鐘,忽然出現(xiàn)大量的內(nèi)容。多么糟糕!

    如何解決呢?Ajax 天生就是異步的。難道不需要進(jìn)行輪詢循環(huán)就能查看何時完成請求嗎?

    結(jié)果證明,并非如此。正如我在 清單 3 中展示的一樣,XMLHTTPRequest 對象所提供的全部內(nèi)容是一個名為 onreadystatechange 的回調(diào)機(jī)制。(多么好聽的名字,讓人想起了 VAX PDP/11s)。


    清單 3. Antipat1a_fixed.html
                            <html><script>
                            var req = null;
                            function processReqChange() {
                            if (req.readyState == 4 && req.status == 200 ) {
                            var dobj = document.getElementById( 'htmlDiv' );
                            dobj.innerHTML = req.responseText;
                            }
                            }
                            function loadUrl( url ) {
                            ...
                            if(req) {
                            req.onreadystatechange = processReqChange;
                            req.open('GET', url, true);
                            req.send('');
                            }
                            }
                            var url = window.location.toString();
                            url = url.replace( /antipat1a_fixed.html/, 'antipat1_content.html' );
                            loadUrl( url );
                            </script>
                            ...
                            

    要查看真實(shí)環(huán)境的演示,請查看在線版本 在新窗口中打開鏈接以查看 antipat1a_fixed.html antipat1a_fixed.html.

    這個新代碼只是查看請求對象是否發(fā)生改變,以響應(yīng) onreadystatechange 回調(diào)。然后,在完成后更新頁面。

    最后的結(jié)果是一個加載神速的頁面。頁面出現(xiàn)后,新的內(nèi)容幾乎是立即填充了頁面框。為什么呢?因?yàn)檎埱笸瓿珊缶土⒓凑{(diào)用了代碼,然后填充頁面。沒有必要將時間浪費(fèi)在無聊的計(jì)時器上。

    輪詢反模式的另一個變體是:頁面反復(fù)向服務(wù)器發(fā)送請求,即使請求沒有發(fā)生變化。請看 清單 4 所示的搜索頁面。


    清單 4. Antipat1b_polling.html
                            <html><script>
                            var req = null;
                            function processReqChange() {
                            if (req.readyState == 4 && req.status == 200 ) {
                            var dobj = document.getElementById( 'htmlDiv' );
                            dobj.innerHTML = req.responseText;
                            }
                            }
                            function loadUrl( url ) {
                            ...
                            }
                            window.setInterval( function watchSearch() {
                            var url = window.location.toString();
                            var searchUrl = 'antipat1_content.html?s='+searchText.value;
                            url = url.replace( /antipat1b_polling.html/, searchUrl );
                            loadUrl( url );
                            }, 1000 );
                            </script><body><form>
                            Search <input id="searchText" type="text">:<br/>
                            <div id="htmlDiv" style="border:1px solid black;padding:10px;">
                            </div></form></body></html>
                            

    要查看真實(shí)環(huán)境的演示,請查看在線版本 在新窗口中打開鏈接以查看 antipat1b_polling.html antipat1b_polling.html.

    您可以看到瀏覽器中的頁面能夠發(fā)揮作用,如 圖 2 所示。


    圖 2. 具有動態(tài)響應(yīng)區(qū)域的搜索區(qū)域
    具有動態(tài)響應(yīng)區(qū)域的搜索區(qū)域

    多么美妙。這樣看來,頁面非常合理。當(dāng)我改變搜索文本時,顯示結(jié)果的區(qū)域也將根據(jù)新的搜索條件改變(也許并不完全如此,但是如果為請求安裝一個真正的搜索引擎,它就會這樣做)。

    問題是 JavaScript 代碼使用 window.setInterval 來不斷地生成請求,即使搜索字段沒有發(fā)生更改。這將消耗網(wǎng)絡(luò)帶寬,并消耗服務(wù)器時間。對于一個流行的站點(diǎn)來說,這可是一個致命的組合。

    解決方法就是對搜索框使用事件回調(diào),如 清單 5 所示。


    清單 5. Antipat1b_fixed.html
                            <html><script>
                            var req = null;
                            function processReqChange() { ... }
                            function loadUrl( url ) { ...  }
                            var seachTimer = null;
                            function runSearch()
                            {
                            if ( seachTimer != null )
                            window.clearTimeout( seachTimer );
                            seachTimer = window.setTimeout( function watchSearch() {
                            var url = window.location.toString();
                            var searchUrl = 'antipat1_content.html?s='+searchText.value;
                            url = url.replace( /antipat1b_fixed.html/, searchUrl );
                            loadUrl( url );
                            seachTimer = null;
                            }, 1000 );
                            }
                            </script><body><form>
                            Search <input id="searchText" type="text" onkeyup="runSearch()">:<br/>
                            <div id="htmlDiv" style="border:1px solid black;padding:10px;">
                            </div></form></body></html>
                            

    要查看真實(shí)環(huán)境的演示,請查看在線版本 在新窗口中打開鏈接以查看 antipat1b_fixed.html antipat1b_fixed.html.

    這里,我將 runSearch() 函數(shù)與搜索框的 onkeyup() 方法關(guān)聯(lián)起來。通過這樣做,當(dāng)用戶在搜索框中輸入內(nèi)容時,我將得到回調(diào)。

    runSearch() 函數(shù)執(zhí)行得非常漂亮。它為調(diào)用服務(wù)器并實(shí)際運(yùn)行搜索的另一個方法設(shè)置了一個超時。如果在設(shè)置之前還沒有超時,那么將清除該超時。為什么?因?yàn)檫@將允許用戶輸入大量的文本;然后,當(dāng)用戶按下最后一個鍵時,第二種方法將運(yùn)行搜索。通過這種方法,用戶將不再被不斷閃爍的顯示打擾。





    回頁首


    沒有檢查回調(diào)返回的結(jié)果

    許多 Ajax 反模式源于對 XMLHTTPRequest 對象機(jī)制的誤解。我經(jīng)常看到的一種情況就是,用戶沒有在回調(diào)中檢查對象的 readyStatestatus 字段。請查看 清單 6 以理解我所說的含義。


    清單 6. Antipat2_nocheck.html
                            <html><script>
                            var req = null;
                            function processReqChange() {
                            var dobj = document.getElementById( 'htmlDiv' );
                            dobj.innerHTML = req.responseText;
                            }
                            ...
                            </code>
                            <p>Everything looks okay. And on small requests, and on some browsers, it's
                            probably fine. But many requests are large enough to call several calls
                            to the <code type="inline">onreadystatechange</code> handler before they
                            finish. So, your callback might be working with incomplete data.</p>
                            <p>The right way to do it is shown in <a href="#list7">Listing 7</a>.</p>
                            <code type="section">
                            <heading refname="list7" type="code">Listing 7. Antipat2_fixed.html</heading>
                            <html><script>
                            var req = null;
                            function processReqChange() {
                            if (req.readyState == 4 && req.status == 200 ) {
                            var dobj = document.getElementById( 'htmlDiv' );
                            dobj.innerHTML = req.responseText;
                            }
                            }
                            ...
                            

    要查看真實(shí)環(huán)境的演示,請查看在線版本 在新窗口中打開鏈接以查看 antipat2_nocheck.html antipat2_nocheck.html.

    沒有太多的代碼,并且它可以在所有瀏覽器上工作。

    我注意到,和其他瀏覽器相比,這個問題在 Windows® Internet Explorer® 7 上尤為突出。Internet Explorer 7 對 onreadystatechange 進(jìn)行多次回調(diào) —— 我的意思是說即使對小的請求也多次進(jìn)行回調(diào)。因此,需要正確編寫處理程序。





    回頁首


    在使用 HTML 更合適的時候卻傳送復(fù)雜的 XML

    在我工作的一家公司中,所有的談?wù)摱际顷P(guān)于 “在網(wǎng)絡(luò)的邊緣實(shí)現(xiàn)智能化”。關(guān)于這個簡單思想的另一個比較有趣的說法就是:通過在桌面上實(shí)現(xiàn)瀏覽器的智能化工作來替代服務(wù)器中的全面處理。

    但是在頁面中實(shí)現(xiàn)智能化意味著在其中使用大量的 JavaScript 代碼。這樣做有一個很大的弊端:瀏覽器兼容性。確實(shí)需要在每個流行的瀏覽器上測試 JavaScript 代碼中每個關(guān)鍵行 —— 或者至少,對客戶最可能使用的瀏覽器進(jìn)行測試。所有這些都意味著大量的工作。以 清單 8 所示的復(fù)雜 Ajax 代碼為例。


    清單 8. Antipat3_complex.html
                            <html><head><script>
                            var req = null;
                            function processReqChange() {
                            if (req.readyState == 4 && req.status == 200 && req.responseXML ) {
                            var dtable = document.getElementById( 'dataBody' );
                            var nl = req.responseXML.getElementsByTagName( 'movie' );
                            for( var i = 0; i < nl.length; i++ ) {
                            var nli = nl.item( i );
                            var elYear = nli.getElementsByTagName( 'year' );
                            var year = elYear.item(0).firstChild.nodeValue;
                            var elTitle = nli.getElementsByTagName( 'title' );
                            var title = elTitle.item(0).firstChild.nodeValue;
                            var elTr = dtable.insertRow( -1 );
                            var elYearTd = elTr.insertCell( -1 );
                            elYearTd.innerHTML = year;
                            var elTitleTd = elTr.insertCell( -1 );
                            elTitleTd.innerHTML = title;
                            } } }
                            function loadXMLDoc( url ) {
                            if(window.XMLHttpRequest) {
                            try { req = new XMLHttpRequest();
                            } catch(e) { req = false; }
                            } else if(window.ActiveXObject) {
                            try { req = new ActiveXObject('Msxml2.XMLHTTP');
                            } catch(e) {
                            try { req = new ActiveXObject('Microsoft.XMLHTTP');
                            } catch(e) { req = false; }
                            } }
                            if(req) {
                            req.onreadystatechange = processReqChange;
                            req.open('GET', url, true);
                            req.send('');
                            }
                            }
                            var url = window.location.toString();
                            url = url.replace( /antipat3_complex.html/, 'antipat3_data.xml' );
                            loadXMLDoc( url );
                            </script></head><body>
                            <table cellspacing="0" cellpadding="3" width="100%"><tbody id="dataBody">
                            <tr>
                            <th width="20%">Year</th>
                            <th width="80%">Title</th>
                            </tr>
                            </tbody></table></body></html>
                            

    要查看真實(shí)環(huán)境的演示,請查看在線版本 在新窗口中打開鏈接以查看 antipat3_complex.html antipat3_complex.html.

    這段代碼從 清單 9 所示的 XML 文件中讀取數(shù)據(jù),然后將它變?yōu)楸砀窀袷健?/p>
    清單 9. Antipat3_data.xml
                            <movies>
                            <movie>
                            <year>1993</year>
                            <title>Jurassic Park</title>
                            </movie>
                            <movie>
                            <year>1997</year>
                            <title>The Lost World: Jurassic Park</title>
                            </movie>
                            <movie>
                            <year>2001</year>
                            <title>Jurassic Park III</title>
                            </movie>
                            </movies>
                            

    可以看到如 圖 3 所示的結(jié)果。


    圖 3. 復(fù)雜的電影清單頁面
    復(fù)雜的電影清單頁面

    這其實(shí)不是糟糕的代碼。只不過是用大量的代碼執(zhí)行一個實(shí)際上相當(dāng)簡單的任務(wù)。產(chǎn)生的頁面一點(diǎn)兒都不復(fù)雜。它不能在客戶端對頁面進(jìn)行排序和搜索。事實(shí)上,幾乎沒有理由對 XML 和 HTML 進(jìn)行復(fù)雜的轉(zhuǎn)換。

    難道不能像 清單 10 那樣讓服務(wù)器返回 HTML 而不是 XML,從而變得更簡單點(diǎn)兒嗎?


    清單 10. Antipat3_fixed.html
                            <html><script>
                            var req = null;
                            function processReqChange() {
                            if (req.readyState == 4 && req.status == 200 ) {
                            var dobj = document.getElementById( 'tableDiv' );
                            dobj.innerHTML = req.responseText;
                            }
                            }
                            function loadUrl( url ) { ... }
                            var url = window.location.toString();
                            url = url.replace( /antipat3_fixed.html/, 'antipat3_content.html' );
                            loadUrl( url );
                            </script><body><div id="tableDiv"></div></body></html>
                            

    要查看真實(shí)環(huán)境的演示,請查看在線版本 在新窗口中打開鏈接以查看 antipat3_fixed.html antipat3_fixed.html.

    事實(shí)上,這樣更加簡單。所有創(chuàng)建復(fù)雜表行和單元格的代碼被替換為頁面中 <div> 標(biāo)記的一組簡單的 innerHTML。 Voilà!

    從服務(wù)器返回的 HTML 如 清單 11 所示。


    清單 11. Antipat3_content.html
                            <table cellspacing="0" cellpadding="3" width="100%">
                            <tbody id="dataBody">
                            <tr>
                            <th width="20%">Year</th>
                            <th width="80%">Title</th>
                            </tr>
                            <tr>
                            <td>1993</td>
                            <td>Jurassic Park</td>
                            </tr>
                            <tr>
                            <td>1997</td>
                            <td>The Lost World: Jurassic Park</td>
                            </tr>
                            <tr>
                            <td>2001</td>
                            <td>Jurassic Park III</td>
                            </tr>
                            </tbody>
                            </table>
                            

    要查看真實(shí)環(huán)境的演示,請查看在線版本 在新窗口中打開鏈接以查看 antipat3_content.html antipat3_content.html.

    對于所有任務(wù),選擇是在服務(wù)器上處理,還是在客戶機(jī)上處理取決于任務(wù)的需求。本文的例子相當(dāng)簡單:提供電影表。如果任務(wù)更復(fù)雜的話 —— 可能會進(jìn)行分類、搜索、添加、刪除或動態(tài)交互(單擊電影名將出現(xiàn)更多信息)—— 那么可以在客戶端使用更加復(fù)雜的代碼。事實(shí)上,在本文的結(jié)尾我將演示在客戶機(jī)上進(jìn)行排序,從而反面論證在服務(wù)器上施加大量負(fù)載的情形。

    也許所有示例中最好的一個就是 Google Maps。Google Maps 執(zhí)行了很好的任務(wù) —— 將富客戶端的代碼與服務(wù)器端的智能映射引擎結(jié)合了起來。我將使用這個服務(wù)作為例子,說明如何確定在哪里執(zhí)行什么樣的處理。





    回頁首


    在應(yīng)該傳送 JavaScript 代碼的時候卻傳送 XML

    所有關(guān)于使 Web 瀏覽器讀取 XML 數(shù)據(jù)源并動態(tài)呈現(xiàn)它們的夸大其辭,可能讓您覺得這是惟一可用的方法。然而,這種想法是錯誤的,因?yàn)榉浅B斆鞯墓こ處熞呀?jīng)使用過 Ajax 傳送技術(shù)來發(fā)送 JavaScript 代碼而不是 XML。請看 清單 12 所示的電影表示例。


    清單 12. Antipat4_fixed.html
                            <html><head><script>
                            var req = null;
                            function processReqChange() {
                            if (req.readyState == 4 && req.status == 200 ) {
                            var dtable = document.getElementById( 'dataBody' );
                            var movies = eval( req.responseText );
                            for( var i = 0; i < movies.length; i++ ) {
                            var elTr = dtable.insertRow( -1 );
                            var elYearTd = elTr.insertCell( -1 );
                            elYearTd.innerHTML = movies[i].year;
                            var elTitleTd = elTr.insertCell( -1 );
                            elTitleTd.innerHTML = movies[i].name;
                            } } }
                            function loadXMLDoc( url ) { ... }
                            var url = window.location.toString();
                            url = url.replace( /antipat4_fixed.html/, 'antipat4_data.js' );
                            loadXMLDoc( url );
                            </script></head><body>
                            <table cellspacing="0" cellpadding="3" width="100%">
                            <tbody id="dataBody"><tr>
                            <th width="20%">Year</th>
                            <th width="80%">Title</th>
                            </tr></tbody></table></body></html>
                            

    要查看真實(shí)環(huán)境的演示,請查看在線版本 在新窗口中打開鏈接以查看 antipat4_fixed.html antipat4_fixed.html.

    這個示例沒有從服務(wù)器讀取 XML,它讀取的是 JavaScript 代碼。然后使用 JavaScript 代碼中的 eval() 函數(shù)獲取數(shù)據(jù),然后再使用這些數(shù)據(jù)快速構(gòu)建表。

    清單 13 展示了 JavaScript 代碼。


    清單 13. Antipat4_data.js
                            [ { year: 1993, name: 'Jurassic Park' },
                            { year: 1997, name: 'The Lost World: Jurassic Park' },
                            { year: 2001, name: 'Jurassic Park III' } ]
                            

    這個功能要求服務(wù)器使用 JavaScript 語言進(jìn)行通信。不過這通常不是什么大問題。大多數(shù)流行的 Web 語言已經(jīng)支持 JavaScript Object Notation(JSON)輸出。

    優(yōu)勢是明顯的。在這個示例當(dāng)中,通過使用 JavaScript 語言,下載到客戶機(jī)的數(shù)據(jù)減少了 52%。同樣,性能也得到了提升。讀取 JavaScript 代碼的速度快了 9%。9% 可能看上去不是很大,但是要記住這是個非常基礎(chǔ)的示例。更大的數(shù)據(jù)塊或者更復(fù)雜的結(jié)構(gòu)需要更多 XML 解析代碼,而所需的 JavaScript 代碼數(shù)量不會變。





    回頁首


    服務(wù)器負(fù)載過重

    在服務(wù)器上執(zhí)行很少的任務(wù)的反面論證是在其上執(zhí)行大量的操作。正如我在前面提到的,這是一個需要權(quán)衡的問題。但是,我想說明的是如何在客戶機(jī)上對電影表執(zhí)行排序,從而為服務(wù)器減輕負(fù)載。

    清單 14 顯示了可排序的電影表。


    清單 14. Antipat5_sort.html
                            <html><head><script>
                            var req = null;
                            var movies = null;
                            function processReqChange() {
                            if (req.readyState == 4 && req.status == 200 ) {
                            movies = eval( req.responseText );
                            runSort( 'year' );
                            } }
                            function runSort( key )
                            {
                            if ( key == 'name' )
                            movies.sort( function( a, b ) {
                            if ( a.name < b.name ) return -1;
                            if ( a.name > b.name ) return 1;
                            return 0;
                            } );
                            else
                            movies.sort( function( a, b ) {
                            if ( a.year < b.year ) return -1;
                            if ( a.year > b.year ) return 1;
                            return 0;
                            } );
                            var dtable = document.getElementById( 'dataBody' );
                            while( dtable.rows.length > 1 ) dtable.deleteRow( 1 );
                            for( var i = 0; i < movies.length; i++ ) {
                            var elTr = dtable.insertRow( -1 );
                            var elYearTd = elTr.insertCell( -1 );
                            elYearTd.innerHTML = movies[i].year;
                            var elTitleTd = elTr.insertCell( -1 );
                            elTitleTd.innerHTML = movies[i].name;
                            }
                            }
                            function loadXMLDoc( url ) { ... }
                            var url = window.location.toString();
                            url = url.replace( /antipat5_sort.html/, 'antipat4_data.js' );
                            loadXMLDoc( url );
                            </script></head><body>
                            <table cellspacing="0" cellpadding="3" width="100%">
                            <tbody id="dataBody"><tr>
                            <th width="20%"><a href="javascript: void runSort('year')">Year</a></th>
                            <th width="80%"><a href="javascript: void runSort('name')">Title</a></th>
                            </tr></tbody></table></body></html>
                            

    要查看真實(shí)環(huán)境的演示,請查看在線版本 在新窗口中打開鏈接以查看 antipat5_sort.html antipat5_sort.html.

    這是一個相當(dāng)簡單的示例。它無法處理那些很可能需要好幾頁顯示的特別長的列表。但是它確實(shí)說明了創(chuàng)建一個能夠快速排序的表非常簡單,并且無需刷新頁面,也不需要服務(wù)器來執(zhí)行麻煩無聊的排序工作。





    回頁首


    結(jié)束語

    分享這篇文章……

    digg 提交到 Digg
    del.icio.us 發(fā)布到 del.icio.us

    我針對 Ajax 編寫了大量文章,并做了大量 Ajax 工作,同時主持 IBM developerWorks Ajax 論壇,所以我了解一些關(guān)于 Ajax 的知識,以及其正確和錯誤的用法。最常見的情況就是開發(fā)人員低估了 Ajax 的復(fù)雜性,他們認(rèn)為它只不過是向?yàn)g覽器發(fā)送 XML、JavaScript 或 HTML 代碼而已。我將 Ajax 平臺視作完整的瀏覽器;實(shí)際上,是完整的流行瀏覽器集,因?yàn)槟仨毩私馑羞@些瀏覽器的特殊要求。

    所有這些都?xì)w結(jié)到一點(diǎn):有大量的有關(guān) Ajax 的知識要學(xué)習(xí),在這個過程中還會發(fā)生很多錯誤。我希望這篇文章能夠幫助您避免一些這樣的陷阱,或者在落入這樣的圈套后幫助您解決麻煩。總之,雖然可以從成功的經(jīng)驗(yàn)中學(xué)到很多知識,然而通常可以從錯誤中學(xué)到更多的東西。



    參考資料

    學(xué)習(xí)

    討論


    關(guān)于作者

     

    Jack D. Herrington 是一位有著超過 20 年經(jīng)驗(yàn)的高級軟件工程師。他是 Code Generation in ActionPodcasting HacksPHP Hacks 這三本書的作者。他還撰寫了 30 多篇文章。可以通過 jherr@pobox.com 與 Jack 聯(lián)系。

    posted on 2007-11-05 00:15 禮物 閱讀(384) 評論(0)  編輯  收藏 所屬分類: Ajax
    主站蜘蛛池模板: 亚洲AV永久无码精品一百度影院 | 精品国产sm捆绑最大网免费站| 三年片在线观看免费大全电影| 最近2019年免费中文字幕高清| 免费看国产精品3a黄的视频| 四虎影在线永久免费观看| 国产偷国产偷亚洲清高动态图| 亚洲AV综合色区无码一区爱AV | 免费毛片毛片网址| 免费精品久久天干天干| 成年人网站免费视频| 国产成人在线免费观看| 亚洲国产精品VA在线观看麻豆| 亚洲免费视频观看| 免费人成动漫在线播放r18| 你懂的免费在线观看网站| 成人毛片手机版免费看| 久久亚洲AV永久无码精品| 亚洲理论精品午夜电影| 美女啪啪网站又黄又免费| 国产好大好硬好爽免费不卡 | 亚洲免费在线视频播放| 亚洲Aⅴ无码一区二区二三区软件| 亚洲国产另类久久久精品小说| 亚洲av乱码一区二区三区香蕉| 免费无码国产在线观国内自拍中文字幕| 全免费a级毛片免费看| 日韩精品视频免费网址| 亚洲Av无码精品色午夜| 亚洲AV电影天堂男人的天堂| 国产激情免费视频在线观看| 国产免费直播在线观看视频| 亚洲视频在线观看| 深夜福利在线视频免费| 美女视频黄的全免费视频| 亚洲人成图片小说网站| 亚洲日韩精品无码专区加勒比☆| 日韩精品无码免费专区午夜不卡| 免费鲁丝片一级观看| 日木av无码专区亚洲av毛片| 一本久久免费视频|