天天看點

Dojo 1.8:向完美架構繼續前行

轉:http://yp.oss.org.cn/software/show_resource.php?resource_id=1641

Dojo 1.8已正式釋出數星期,作為Dojo的鐵杆粉卻直到今天才來總結,實在心有不安,但這并不妨礙我們來看一看那些讓人眼前一亮的新特性。作為曆史最悠久的 RIA架構,Dojo的發展一直不冷不熱。比起後來者JQuery的大紅大紫,Dojo則默默的按照自己的步伐堅定的前行着。而對完美架構的追求,則構成 了Dojo前行的主旋律,這也使得Dojo一直擁有一批堅定的支援者。 

Dojo顯然并不重視設計靈巧的API,但卻非常看重程式設計思想的應用,以及對前端架構的研究。我們現在就來看看Dojo 1.8是如何在這個方向上繼續努力着。

1. 對匿名子產品的徹底支援:dojo/parser支援了對子產品ID的解析

從上個1.7版本開始,Dojo全面引入了AMD(Asynchronous Module Definition)的機制。這使得每個子產品的邏輯都完全擁有自己的閉包,通過傳回值來暴露API接口或者資料。這樣的子產品是完全匿名的,AMD Loader會根據子產品ID(例如:dojo/html)來映射到路徑去尋找對應的檔案。比起舊的Loader中每個子產品都需要聲明 dojo.provide('dojo.html'),AMD機制真正做到了DRY原則(Don't Repeat Yourself),子產品路徑就是唯一辨別符,不再需要在子產品内部重複指定自身路徑。這樣的架構也讓Dojo幾乎可以做到完全沒有全局變量的存在,說幾乎 是因為1.8之前有一個例外:通過Html聲明方式建立的widget仍然需要一個全局的data-dojo-type屬性:

<input type="text" data-dojo-type="dijit.form.TextBox"/>
      

這裡的dijit.form.TextBox就是一個全局變量,表示一個TextBox控件的類名。在原來的dijit/form/TextBox子產品中,必須有一個定義:

declare('dijit.form.TextBox', [], {});
      

dojo的parser會根據這個Widget的data-dojo-type去找對應的實作類。是以,盡管作為AMD子產品已經是匿名,但其卻有一個隐藏的全局變量在子產品内定義,導緻其自身其實并不是真正意義上的匿名,即不是完全的DRY。

然而在1.8中,這最後一個局限也完全消失了。dojo/parser能夠根據子產品ID來找到TextBox的實作,現在我們可以這樣聲明一個Widget:

<input type="text" data-dojo-type="dijit/form/TextBox"/>
      

盡管表面上看來,隻是把點(.)換成了斜杠(/),但從程式設計的思想上來看,則可以讓子產品減少了一個概念:一個Widget就隻有一個辨別,就是子產品ID。而不是之前既有子產品ID,又有Widget類名這樣容易混淆的情形。概念上的簡單和清晰是了解易維護的重要前提。

本質上來看,AMD取代傳統的dojo.require無關乎性能,僅關乎于架構。AMD能讓你沿着正确的路線開發松耦合的子產品,讓應用更加容易了解和維護。而Dojo正在不斷的完善着細節,幫助我們設計出更好的應用架構。

2. 讓每個Widget都有插件機制:新的data-dojo-mixins屬性

插件機制是建立靈活可擴充應用的一個最佳實踐,而現在Dojo通過這個全新的屬性全面實作了插件機制,讓Dojo的Widget在使用時可以靈活決 定自己需要的特性。因為這個屬性的存在,Widget的開發也将可以更加子產品化,每一組功能都能獨自定義。在使用的時候,根據具體的使用場景,來決定是否 啟用此功能。比如,在dojox中提供了最近較為流行的TreeMap元件。子產品dojox/treemap/TreeMap本身僅僅包含了最基礎的功 能。而對于鍵盤支援,色塊拆分等功能則通過可插拔的子產品來實作:dojox/treemap/Keyboard和dojox/treemap /DrillDownUp子產品。這樣的附屬子產品可以了解為插件,按照需要将其添加到data-dojo-mixins屬性中即可開啟相應的功能。

<div data-dojo-type="dojox/treemap/TreeMap" data-dojo-mixins="dojox/treemap/Keyboard, 
dojox/treemap/DrillDownUp"></div>
      

在這裡,data-dojo-mixins屬性中用逗号隔開的子產品就可以看成一個個插件。不僅新控件可以利用插件機制,為現有元件添加新的功能,也 可以通過提供插件來實作。比起派生一個新類來實作此功能,插件是可以通用的。例如:假設要為dijit/form下的TextBox,Select等表單 控件添加語音識别的功能,可能隻需要寫一個my/voice/Recognizer子產品,這樣具有set('value', value)這樣接口的Widget都将能靈活選用這個元件,而不需要為每個Widget都派生一個新的類。而對于多個插件的功能組合,則更顯然 data-dojo-mixins會非常合适。

現在看到的是聲明方式建立的Widget我們可以很好的利用data-dojo-mixins實作插件機制。那麼對于動态建立的Widget呢?其實這1.8之前已經可以實作:

var treemap = new (declare(['dojox/treemap/TreeMap', 'dojox/treemap/Keyboard',
 'dojox/treemap/DrillDownUp']))(arguments);
      

子產品的靈活性,一直是Dojo的重點關注。從引入AMD開始,Dojo就提出了base-less的概念,即Dojo架構可以配置為沒有任何核心 庫,所有的子產品都按需加載。這要求每個子產品提供的功能獨立而精簡,進而能夠實作最終僅僅加載需要的代碼的目的。而data-dojo-mixins屬性則 是可以幫助我們将功能拆分并子產品化到極緻。這在目前JavaScript代碼普遍臃腫的大環境下無疑是一個讓人眼前一亮的概念和做法。

3. 契約式程式設計:dojo/promise

契約式程式設計是另一種很好的程式設計實踐,它的目标是讓程式的各個子產品各司其職,僅僅關注自己需要完成的事情,而不用去關心其它子產品該關心的事情。進而可以降低子產品之間的耦合度,同時也讓程式在語義上更加容易了解。其概念已經非常成熟,讀者可以搜尋相關資料,這裡不再贅述。

雖然在1.8之前,Dojo可以通過dojo.Deffered實作契約程式設計的思想,但是終歸不是很正式。而從1.8起,Dojo提供了正式的類和API來全面支援契約式程式設計:

dojo/promise/Promise - 契約核心類,所有實作契約機制的類都能夠提供一個Promise類的執行個體。比如dojo/Deffered,專門對應于異步的情形。

dojo/errors/CancelError - 當一個契約被未知原因的取消時,提供此預設錯誤。

dojo/promise/all - 接受多個契約作為參數,傳回一個新的契約。隻有當多個契約都得到滿足時,新契約才會得到滿足。從本質看,這取代了原來的dojo/DeferredList。

dojo/promise/first - 接受多個契約作為參數,傳回一個新的契約。隻要其中一個契約得到滿足時,新契約立刻滿足。

舉例:

require(["dojo/promise/all", "dojo/Deferred", "dojo/dom", "dojo/on", "dojo/json", "dojo/domReady!"],
function(all, Deferred, dom, on, JSON){
  function googleRequest(){
    var deferred = new Deferred();
    setTimeout(function(){
      deferred.resolve("foo");
    }, 500);
    return deferred.promise;
  }
  function bingRequest(){
    var deferred = new Deferred();
    setTimeout(function(){
      deferred.resolve("bar");
    }, 750);
    return deferred.promise;
  }

  function baiduRequest(){
    var deferred = new Deferred();
    setTimeout(function(){
      deferred.resolve("baz");
    }, 1000);
    return deferred.promise;
  }
  on(dom.byId("startButton"), "click", function(){
    dom.byId("output").innerHTML = "Running...";
    all([googleRequest(), bingRequest(), baiduRequest()]).then(function(results){
      dom.byId("output").innerHTML = JSON.stringify(results);
    });
  });
});
      

通過這段代碼可以看到,對每個搜尋引擎的搜尋請求都傳回一個契約,外界程式隻需關心這個契約。在搜尋完成之後,契約會通過調用resolve方法來 告訴外界自己已完成任務。進而外界僅需要關心什麼時候開始搜尋,以及搜尋完成後自己該做什麼。其邏輯和語義都非常清楚和合理。通過promise提供的 all,first方法,外界可以更靈活的對契約進行管理。

通過promise,請求發起和結果處理過程被嚴格的區分開來,你将不得不分開代碼處理邏輯,這種隐含的硬性規定讓代碼程式結構更加良好,代價是會讓初用者覺得上手困難,但是一旦習慣,帶來的好處将是一勞永逸的。

4. 更為統一的IO子產品:dojo/request

所有的RIA架構都會通過隐藏底層細節,提供統一的一緻的API來實作跨浏覽器的支援。而現在Dojo正在将跨浏覽器擴充到跨JavaScript 環境。dojo/request正是有這樣需求的一個API。在浏覽器端,通過XMLHttpRequest擷取資料,而在NodeJs之類 JavaScript環境則用NodeJS提供的檔案系統API來實作。

dojo/request這個package引入了一種用于異步請求的全新架構。這個子產品将使用者從具體的請求細節中抽象出來,也就是說,使用者無需關 心請求是如何發生的。dojo/request正是基于上文提到的dojo/promise來建構的。當引入dojo/request子產品時,将根據運作 平台自動傳回對應的實作。比如,浏覽器中就會使用dojo/request/xhr,而NodeJS平台則會使用dojo/request/node。

下面的代碼示範了dojo/request的基本用法:

require(["dojo/request"], function(request){  
    var promise = request(url, options);  
    promise.then(  
        function(data){  
        },  
        function(error){  
        }  
    );  
    promise.response.then(  
        function(response){  
        },  
        function(error){  
        }  
    );  
    request.get(url, options).then(...);  
    request.post(url, options).then(...);  
    request.put(url, options).then(...);  
    request.del(url, options).then(...);  
});
      

詳細的dojo/request的介紹大家可以參考Dojo中文部落格的文章:深入淺出dojo/request: http://blog.csdn.net/dojotoolkit/article/details/7991286

5. 面向移動裝置的全面支援:dojo/touch,dojox/mobile

dojo/touch子產品的目的是為了讓面向PC的Web應用也能夠運作在移動裝置上,它提供了許多鍵盤滑鼠事件和手勢操作的映射。進而讓普通的控 件在移動裝置上也能正常工作。現在Dojo自帶的控件基本都采用了dojo/touch來實作對移動裝置的支援。對于自定義的控件,也可以通過dojo /touch子產品來實作這一功能。

Mobile是最近的熱點領域,HTML5能夠讓同一份代碼運作在不同的平台上。雖然有些類型的應用并不适合使用HTML5,但大多數資訊展示和簡 單互動的移動應用非常适合使用HTML5,能夠大大減少開發維護成本。而Dojo 1.8在對Mobile裝置提供了大力的支援,提供了多達28個全新的控件,比如 TreeView,ScrollablePane,DatePicker,GridLayout等常用控件。通過PhoneGap+Dojo把HTML5 封裝成手機應用,将是一個完全免費的開源跨平台移動開發解決方案。這也正是IBM使用的解決方案。

小結

Dojo一直非常看重程式設計思想的使用,以及前端架構的優化。比如1.8中的契約式程式設計,AMD增強,等等。雖然提供了大量新的API,但是為了保證 向後相容仍然保留了原有的API,隻是會辨別為已過期。這些過期的API将會在明年釋出的2.0版本中徹底删除。這在一定程度增加了更新的難度,但是為了 軟體的健壯和可維護性,這是值得付出的代價。1.8和1.9版本也使得到2.0的過渡更加平滑。總體來說,我相信随着大家對Dojo的深入了解,Dojo 一定會出現在越來越多的大型項目之中。

參考資源:

Dojo 1.8 下載下傳:http://dojotoolkit.org

Dojo 1.8 Release Notes: http://dojotoolkit.org/reference-guide/1.8/releasenotes/1.8.html

Dojo中文部落格:http://blog.csdn.net/dojotoolkit

Dojo新浪微網誌:http://weibo.com/dojotoolkit

繼續閱讀