Dojo框架:誤解與現實

 

隨着Ajax技術的流行,越來越多的Web應用使用Ajax技術來提高用戶體驗。使用Ajax技術的一個重要優勢是不需要額外的瀏覽器插件支持,只需要使用瀏覽器原生的API,並利用JavaScript來操作即可。使用原生API時會遇到的兩個比較大的問題是瀏覽器兼容性和底層A代PI接口帶來的編程複雜性。同樣的功能在不同的瀏覽器上的實現方式是存在差異的。如果一個應用希望支持不同的瀏覽器,則開發人員需要添加很多的瀏覽器檢測或嗅探的代碼。比如同樣的事件綁定功能,在IE上使用attachEvent,而在其它瀏覽器上則使用addEventListener。除了兼容性問題之外,瀏覽器提供的原生API的接口一般都比較適合用來執行細粒度的操作。當需要完成一些相對複雜的操作的時候,使用原生API接口會使得代碼比較繁瑣。以一個DOM查詢爲例:在當前文檔樹中查找給定ID的節點的所有給定標籤的直接子節點。對於這樣一個查詢,使用原生DOM API的話,則會需要使用getElementById來查找節點,通過childNodes來獲取子節點列表以及比較節點的標籤名稱等。所要求的碼量會比較大。

JavaScript框架的出現,正是爲了解決這兩個比較大的問題,而不同的JavaScript框架也提供了各自額外的附加價值。目前可以使用的JavaScript框架非常之多,比較流行的也有十多種。這些流行的JavaScript框架包括jQueryDojoYUIMooToolsPrototypeExt JSGoogle Closure等。這些不同的框架有着各自不同的優勢和不足,也有着對應的不同的適用情景和範圍。由於工作的關係,筆者對Dojo框架的使用最多,對於其它框架也有一定的瞭解。本文的目的是希望澄清一些對於Dojo框架的誤解,從而幫助開發人員選擇合適的框架。

在開始之前,首先簡要介紹一下Dojo框架的基本結構。Dojo框架由四個部分組成:Dojo基本庫、核心庫、Dijit和擴展庫。基本庫包含最基本的功能,核心庫是基本庫的擴展,Dijit是用戶界面庫,而擴展庫則是各式各樣的擴展組件。

滿足Ajax應用開發基本的需求

Dojo和其它框架一樣,都試圖滿足Ajax應用開發中的最基本的需求。這些基本的需求包括前面提到的瀏覽器兼容性和原生API的接口粒度問題,以及一些典型的應用場景。具體來說,應該包括下面一些功能集:JavaScript語言增強、XMLHttpRequest封裝、DOM查詢與操作和事件處理等。而瀏覽器兼容性體現在這些功能集在不同瀏覽器上的效果是一樣的。

從Dojo框架來說,對這些功能集的支持是比較豐富的。在JavaScript語言增強方面,對數字、字符串、日期類型、數組和JavaScript方法等有很多的增強功能。在I/O傳輸方面,除了常用的XMLHttpRequest 之外,還支持iframe和<script>等。dojo.query提供了類似於jQuery的DOM查詢和操作的能力。 dojo.connect不但可以用來綁定DOM元素上的事件,還可以連接到JavaScript方法的執行上。

上面提到的這些基本功能都出現在Dojo基本庫和核心庫中。打包壓縮之後的代碼大小在80K左右,不會對整個頁面的代碼量造成很大的影響。

面向對象JavaScript與函數式JavaScript

面向對象的編程思想是目前比較流行的一種編程方法學。這種編程思想也被主流的編程語言所支持,包括Java、C++和C#等。很多開發人員都習慣於用面向對象編程思想中的類和對象的概念去進行分析和設計,再用相應的編程語言來完成實現。面向對象編程思想中的封裝、繼承和多態等概念,也比較適合對真實的問題域進行分析和抽象。在某些Ajax應用中,前端部分的邏輯比較複雜,同時也需要實現一部分業務邏輯。所需的代碼量已經不是幾個簡單的方法這個級別,而需要進行完整的建模、分析和設計。很多開發人員會自然而然的使用面向對象的編程思想對Ajax應用的前端進行分析和設計。但是JavaScript語言並不是一門面向對象的編程語言,它在很多方面都不同於傳統的面向對象編程語言。因此在從分析和設計到實現的過程中,會出現阻抗不匹配的情況。對於這種不匹配的情況,解決的辦法不外乎兩種:一種是改變分析和設計時的思路,而另外一種則是對JavaScript語言進行面向對象方面能力的增強。

JavaScript語言在設計的時候,就帶有一些面向對象編程語言的影子,如new操作符和通過原型(prototype)可以實現的繼承機制等。通過JavaScript的這些語言特性,可以實現完整的面向對象能力。Dojo框架所提供的面向對象方面的能力非常完備。最典型的用法是可以通過dojo.declare()方法來聲明一個類,並且可以支持多繼承。使用Dojo可以很快的寫出經典的支持多繼承的面向對象的示例,如:

dojo.declare("Human", null, {
  think : function() {}
});
dojo.declare("Machine", null, {
  work : function() {}
});
dojo.declare("Robot", [Machine, Human], {
  turingTest : function() {}
});

Dojo通過其面向對象JavaScript的支持,在一定程度上解決了前面提到的阻抗不匹配的問題。但是在全面使用Dojo提供的面向對象JavaScript 的能力的時候,要注意會帶來的一些風險。首先要理解的是函數在JavaScript中是一等公民,可以作爲對象的屬性以及函數的參數和返回值來使用。 JavaScript中的閉包也是一個非常強大的概念,妥善使用的話可以寫出簡潔而強大的程序。如果完全按照Dojo所抽象出來的面向對象的方式來使用 JavaScript,會丟失掉JavaScript語言本身的一些好的特質。所以不建議開發人員一開始就深入到Dojo的面向對象JavaScript 的世界裏面,而是首先多瞭解一些JavaScript語言本身的特徵。比如理解JavaScript中的原型鏈(prototype chain)、this的含義、new操作符、執行上下文(execution context)和作用域鏈(scope chain)等。否則的話,一旦形成了思維定勢,可能會無法理解其它框架或是庫的實現方式,畢竟不是所有的庫都採用了Dojo這樣的方式來實現。其次要認識到在性能方面可能帶來的影響。熟悉Java的開發人員可能都習 慣於在設計的時候使用很多個細分的Java類,這些類之間通過精細的協作來完成具體的任務。這對Java來說是合理的。而對於運行在瀏覽器中的 JavaScript這種解釋執行的語言來說,過多的對象和消息傳遞會對性能造成一定的影響,而性能又是Ajax應用中需要關注的重要因素。

面向對象編程的思想進入到Web應用的前端開發領域,是一件好的事情。它使得廣大前端開發人員可以用自己熟悉的方式來設計和開發Web前端。但是在 JavaScript語言本身和瀏覽器這個運行平臺的雙重限制下,需要適度的使用,不過未來的前景是樂觀的。JavaScript是ECMAScript的方言之一,目前的實現基本都遵循的是ECMAScript第三版規範。而ECMAScript第五版規範已經發布。值得一提的是,ECMAScript第四版嘗試在JavaScript中引入類、包和名稱空間等概念,不過由於各種原因被放棄了。而第四版的這些思想形成了新的正在開發中的ECMAScript Harmony項目。按照標準化過程的速度,短期之內JavaScript語言是不會擁有傳統面向對象編程語言的類的結構,而包和名稱空間的結構則需要等待更長的時間。不過這一天終會到來。隨着V8ChakraSquirrelFishCarakan等新的JavaScript引擎的出現,JavaScript語言本身的執行性能將會有大幅度的提升。這兩個方面的改進會使得以面向對象的思想編寫JavaScript程序變得更加自然。

Dojo的複雜度過高

Dojo是一個龐大和複雜的庫,其中包含數以百計的模塊。每個模塊都有自己的源代碼、測試用例、演示頁面和文檔說明等。從這個角度來說,Dojo的複雜度高於jQuery等其它框架。對於Ajax應用來說,有兩種常見的風格:Ajax Lite和Ajax Deluxe。對於Ajax Lite風格的Ajax應用來說,jQuery等輕量級框架是比較好的選擇,可以很方便的對頁面做出修改。只使用Dojo基本庫也是不錯的選擇。對於Ajax Deluxe風格的應用來說,Dojo可以體現出它的價值。在開發風格的複雜Ajax應用時,一套完整的用戶界面組件庫是非常有必要的,可以極大節省開發人員的時間。在這個層次上,Dojo和jQuery採用了不同的做法。jQuery非常小巧靈活,暴露給開發人員的概念非常少。$、CSS選擇器和方法級聯,就已經差不多是全部了。社區也貢獻了非常多的jQuery插件,豐富了jQuery本身的功能。這是一種自下而上的做法,先有一個穩健的基礎,再依靠社區的力量發展壯大。Dojo的做法則正好相反。Dojo中已經集成了很多模塊,滿足各種不同的需求。這些模塊背後都體現了相同的設計思想。以用戶界面與數據的關係爲例,Dojo定義了dojo.data API來抽象異構數據源的訪問接口。需要訪問數據的用戶界面組件都通過此API來訪問數據。這種做法帶來的問題是暴露給開發人員的概念過多,給開發人員的感覺是完成一件簡單任務的起步就非常困難。不過這種做法也爲框架本身的維護和擴展帶來了方便。當構建一個複雜的Ajax應用的時候,這種複雜性有時候是非常必要的,尤其在團隊工作的時候。對於一個複雜的問題,總是會需要一些稍微複雜的設計來保證解決方案的可維護性。與其選擇自己去處理它,還不如交給一個設計良好的框架來完成。

對於開發Ajax Lite風格的Ajax應用來說,也可以從Dojo基本庫開始。當需要的時候再考慮Dijit庫。

Dojo不易上手,學習曲線較陡

前面提到了Dojo的複雜性,這種複雜性會使得開發人員很難在較短的時間內入門。開發人員要理解和接受的概念過多。Dojo框架本身也提供了兩種類型的編程風格,即前面提到的面向對象和函數式的方式。Dojo基本庫和核心庫比較多的採用的函數式的風格,比如dojo.connect()、dojo.xhrGet、 dojo.declare()和dojo.query()等。開發人員可以把這些方法當成工具來使用。對於Dojo基本庫和核心庫來說,只需要查看相關的 API說明文檔就可以知道每個方法的參數、返回值和需要注意的地方。Dijit庫則使用的是面向對象的風格。Dijit庫包含的是一些用戶界面組件,組件內部封裝了相關的邏輯。開發人員需要通過new操作符來在頁面上創建出組件的實例。這樣的使用方式對熟悉Java圖形界面組件庫,如SWT/JFace和 Swing的開發人員來說,是比較好理解的。而兩種編程風格雜糅在一起,會對開發人員的理解造成一定的問題。在這點上,jQuery UI的做法就更加可取一些。在Dijit裏面創建一個對話框並打開的做法是:

var dialogNode = dojo.query("#dialogNode")[0];
var dialog = new dijit.Dialog({});
dialog.open();

而在jQuery UI裏面,使用的方式是:

$("#dialogNode").dialog({autoOpen : false});
$("#dialogNode").dialog("open");

jQuery UI在編程風格上與jQuery是相似的,採用的都是函數式的風格。這種一致性對開發人員來說是更加合適的。

用戶界面組件

在Ajax應用的前端界面部分,少不了用戶界面組件的支持。HTML語言本身提供了一些基本的元素,包括常見的div、span和表單元素等。使用這些基本元素可以構造出複雜的用戶界面。但是相對於桌面應用開發時可以使用的組件來說,HTML語言的這些元素還是過於基本,無法快速高效的進行開發。比如一些常見的界面組件,如菜單、對話框、樹形控件、表格控件、日期和時間選擇器和富文本編輯器等,都需要開發人員自己來實現,不僅耗時而且質量也比較難以保證。對於這種情況,Dojo框架提供了自己的用戶界面組件編程模型Dijit,以及一些高質量可定製的標準用戶界面組件。通過使用和定製這些標準組件,可以很快速的構建出應用的界面。開發人員也可以根據編程模型,開發出自己應用所需的特有組件。

從這個角度來說,Dojo框架希望提供的是與桌面開發相似的用戶界面組件庫,比較適合在集成開發環境中使用。開發人員通過拖拽的方式來添加組件,並設置組件的相關屬性。通過這種方式,可以幫助開發人員更快的構建複雜的Ajax應用。Dijit庫的好處在於提供了一個設計良好的Web應用前端組件編程模型,以及在這模型基礎之上的衆多參考實現。這就爲創建一個良好的組件共享平臺打下了基礎。實際上,在Dojo擴展庫中就已經有不少由社區貢獻出來的組件。這個編程模型的一些優點在於:

  • 完整的生命週期管理。從創建到銷燬,生命週期中的不同階段都允許開發人員進行定製和擴展。
  • 基於HTML模板的方式快速創建用戶界面。支持在模板中以聲明式的方式綁定 DOM元素和事件。
  • 統一的組件接口,包括屬性設置和獲取和事件綁定等。
  • 完善的主題支持,可定製的組件外觀。

從前端開發人員的角度來說,如果對用戶界面的組件化是一個必要的設計考慮,則Dijit是一個比較好的起點。

Dojo的性能比較差

對於Web應用來說,性能是一個非常重要的因素。既然JavaScript庫是目前Ajax應用開發中必不可少的一部分,那麼性能方面的差別會成爲選擇的重要因素。一般對Dojo框架的認識是速度很慢。實際上,影響Web應用性能的因素非常多,包括HTTP請求的個數、請求響應內容的大小、JavaScript代碼的執行時間、頁面元素的重新佈局和排列次數等。把頁面的速度過慢單純歸咎於 JavaScript庫本身,是有失偏頗的。

對於Dojo庫的一個比較常見的看法是Dojo庫過於龐大,需要加載比較多的資源文件,導致頁面的加載速度過慢。確實,與jQuery和Prototype等JavaScript庫相比,Dojo庫分發包偏大。Dojo 1.5的分發包是2M,而jQuery 1.4.4壓縮之後的大小才26K。不過兩者的功能是不同的。Dojo庫所提供的功能更多,所包含的代碼量自然更大。造成這一原因的問題在於開發環境和部署環境的不同。對於jQuery來說,開發環境和部署環境是相同的,只需要複製單個JavaScript文件即可。而對於Dojo則沒有這麼簡單,這中間缺少的步驟是構建過程。

Dojo採用的是模塊化的設計,其中包含非常多的模塊,分佈在Dojo基本庫、核心庫、Dijit庫和擴展庫中。通過dojo.require可以聲明在頁面中需要加載的模塊。這個加載過程會需要從服務器端下載所需的JavaScript文件,從而導致在運行時過多的HTTP請求。Dojo的構建系統會把來自不同模塊的JavaScript文件打包在一個文件中,只需要在頁面上引用打包好的單個JavaScript即可。使用Dojo的構建過程,需要下載Dojo SDK,在utils/buildscripts/profiles目錄下面添加一個構建文件,如myDojo.profile.js。在該文件中聲明所需要包含的模塊,如:

dependencies = { 
    layers: [ 
       { 
           name: "dojo.js",
           dependencies: [ 
                "dijit.layout.BorderContainer",  
                "dijit.layout.ContentPane", 
                "dojox.layout.ExpandoPane", 
                "dojox.image.Lightbox" 
           ] 
       } 
    ], 

    prefixes: [ 
        [ "dijit", "../dijit" ], 
        [ "dojox", "../dojox" ] 
    ] 
} 

再通過運行

build profile=myDojo 

action=release就可以啓動構建過程,最後在release目錄下面的就是可以直接複製到部署環境的Dojo庫。Dojo的構建過程使用的是運行在Rhino上的JavaScript代碼,可以很好的與Apache Ant集成。也可以選擇使用其它圖形化構建工具,如:Dojo Toolbox

參考資料

 

原文鏈接:http://www.infoq.com/cn/articles/dojo-misunderstanding-reality

發佈了56 篇原創文章 · 獲贊 3 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章