在 Node.js 上使用 Dojo

fmms 12年前發布 | 39K 次閱讀 Node.js JavaScript開發

簡介: Node.js 讓服務器端和客戶端的編程語言得到了統一,而 Dojo 則讓開發框架得到了統一。得益于優良的架構,Dojo 能同時在服務器端和客戶端運行,從而讓 Web 開發人員用同一種語言,同一個框架就能實現完整的 Web 應用。

在 Node.js 上使用 Dojo

Node.js 最近非常火熱,不僅開源社區對其非常關注,甚至微軟對其也提供了官方的支持,從而讓 Node.js 也能運行于 Windows 系統,這為 Node.js 的進一步流行奠定了基礎。本文將介紹 Node.js 和 Dojo 的模塊管理機制,并在此基礎上詳細介紹在 Node.js 上運行 Dojo 框架的方案。最后通過一個例子,演示如何用 Dojo 的 DTL 模塊來解析一個基于 Django 模板語言的模板文件。

一個普遍的看法是 Node.js 讓 JavaScript 成為了服務器端語言,于是自然很多人都把 Node.js 看成了一個 Web Server。但實際上并非如此,Node.js 只是一個 JavaScript 宿主環境,它解釋并運行 JavaScript,同時提供了很多原生對象(Native Object)讓 JavaScript 可以做更多的事情,例如進行網絡通信、文件處理等等。就像,您可以用 Perl、Python 寫一個 Web Server 一樣,您也可以用 JavaScript 寫 Web Server。Node.js 適合創建 Web Server,因為它能高效的處理并發請求,但它自身并不是一個 Web Server。澄清這一點,我們就完全可以像用 Perl 一樣來用 JavaScript,讓它成為一種工具語言。當出現產品級的基于 Node.js 的 Web Server 時,我們也就能更加容易的上手進行 Web 服務器端開發。

為什么要在 Node 上運行 Dojo

JavaScript 本身是一個設計非常精簡的語言,功能相對簡單,因為它的初衷并不是用來開發復雜的應用,而只是用于自動化的來操縱瀏覽器。面對日益復雜的前端應用,已經出 現了很多類庫來解決這個問題,比如 jQuery、ExtJs、Dojo、YUI。這些類庫除了實現了瀏覽器兼容的 API,同時還有一大部分功能是純粹的用來增強 JavaScript 的功能。而這部分功能,正是服務器端和瀏覽器端通用的,我相信如果在這方面提供一致性,一定是廣大 Web 開發人員所喜聞樂見的,這也是我寫這篇文章的目的。

這么多類庫之中,Dojo 是所有當前類庫中最適合運行于 Node.js 的,原因有四:

  1. Dojo 和 Node.js 都基于 CommonJS 的 Module 規范。
  2. Dojo 天然支持 Node.js,很好的對瀏覽器相關代碼做了隔離。啟動腳本能自動檢測 Node.js 運行環境檢測,無需任何修改即可直接使用。
  3. Dojo 所采用的單元測試框架和打包工具都是用 JavaScript 寫成,可以直接在 Node.js 上運行。從而,Dojo+Node.js 可以完成整個應用開發的生命周期。
  4. Dojo 有完整的面向對象體系,適合大型應用的開發。

Dojo 一直以來都這樣定義自己:JavaScript toolkit,而并不是 Ajax Library 之類的簡單的以前端應用為目標的框架。可見增強 JavaScript 功能是 Dojo 的一個重要目標,它的強大的面向對象的機制,事件機制,豐富的工具庫,已經為大型前端應用的開發提供了很好的基礎。而現在,它將又能在 Node.js 上發揮作用。

Node.js 和 Dojo 的模塊加載機制

Node.js 和 Dojo 都遵循 CommonJS 的模塊相關規范。Node.js 支持的是 Module1.0 規范,而 Dojo 支持的是 AMD(Asynchronous Module Definition,即異步模塊定義)規范。雖然是兩個規范,但它們都是描述了模塊的定義和加載機制,有很多共同點。這就為 Dojo 運行于 Node 提供了天然的基礎。在規范中,JavaScript 文件和模塊是一一對應的關系,每個文件就是一個模塊,模塊之間可以通過相對路徑來引用。

對于 Node.js,要使用一個模塊非常簡單,直接用 Module1.0 規范中定義的 require 函數即可,例如:

 var fs = require('fs'); 
 var content = fs.readFileSync('filePath' ,' utf8' ); 

這里的 fs 是 Node.js 自帶的文件系統操作的模塊,可以通過它的標識“fs”來載入它,從而可以調用其提供的方法。這種模塊依賴的方法和傳統編程語言類似,例如 Java 的 import,C# 的 use。

但對于 Dojo 支持的 AMD 規范,則定義的是一個異步載入機制,稍微復雜。因為這個規范強調的是異步,就需要通過一個回調函數來使用模塊,這個回調函數會在依賴的模塊載入完成之后被調用,例如:

 define(['dojo/date'], function(date){ 
 var zone = date.isLeapYear(new Date());// 獲取當前是否閏年
 }); 

這里的 define 函數是由 AMD 規范定義的,其第一個參數是一個數組,包含了本模塊需要依賴的模塊,當這些模塊載入完成后,會調用第二個參數:一個回調函數。并按順序將依賴的模塊作為參 數傳遞給這個回調函數,供本模塊使用。關于 define 函數的詳細用法這里不多介紹,有興趣的可以去查看相關規范文檔。我們僅需要知道它是一個異步的模塊定義和加載機制。

Dojo 中所有的模塊都是通過 define 函數定義的,很顯然,不支持 AMD 規范的 Node.js 是不認識 define 函數,不能直接執行這些模塊的。因此,Dojo 必須自己維護模塊的加載和執行,這也完全符合 Dojo 在瀏覽器端的行為,只是讀取模塊代碼的邏輯從 HTTP 請求轉換到了讀取文件,其它邏輯維持不變。在 Dojo 的初始化代碼中已經包含了對 Node.js 環境的檢測,會自動根據環境使用不同的方法載入模塊。

在 CommonJS 規范的基礎上,Node.js 和 Dojo 還都另外引入了類似的包(package)的概念。所謂一個包就是一個文件夾,在 Node.js 下可以直接 require('packageIdentifer' ),而 Dojo 則是通過 define(['packageIdentifier' ], callback) 來使用一個包。這時 Node.js 會尋找文件夾下的 index.js 或者 index.node 模塊,而 Dojo 則尋找的是 main.js 模塊。同樣,因為應用是運行于 Dojo 框架之下,包的概念以 Dojo 的實現為準。

如果把模塊的加載理解為 Java 中的 ClassLoader,那么 Dojo 就是實現了自己的 ClassLoader,來取代 Node.js 自身的行為。因此,要在 Node.js 上運行一個基于 Dojo 的應用,用的是類似下面的命令:

 node <dojoroot>/dojo.js load=xxx 

這個命令告訴了 Node.js 應該執行 dojo.js 這個模塊,從而啟動了 Dojo 框架。而后面的參數 load=xxx 則是告訴 Dojo 應該執行 xxx 這個包(package)。這里的 xxx 就是您的應用程序的入口位置。因為 Dojo 已經接管了模塊的管理,所以這里運行的就是 xxx 這個包下的 main.js 模塊。

理解了這些內容,我們就可以進一步了解如何配置 Dojo,讓其在 Node.js 上運行基于 Dojo 的應用程序。

在 Node 上運行 Dojo

下面通過一個簡單的例子來看,如何在 Node 上運行基于 Dojo 的程序。

1. 引入并配置 Dojo

我們知道,在瀏覽器端引入 Dojo 之類的框架,首先需要在頁面中引入框架自身,通常是通過 <script> 標簽引入,在引入的同時,還可以傳遞參數,對于 Dojo 來說,可以通過兩種途徑,一種是在 <script> 標簽中加入屬性,例如:

<script type=”text/javascript” src=”dojoroot/dojo/dojo.js” djConfig="isDebug:true"></script>

這里的 djConfig 就是傳遞給 Dojo 的配置參數,設置了 isDebug 開啟狀態,從而可以輸出調試信息。另一種方式是通過定義一個名為 dojoConfig 的全局變量,在其中對 Dojo 對其配置:

 <script type=”text/javascript”> 
 Var dojoConfig = { isDebug: true }; 
 </script> 
 <script type=”text/javascript” src=”dojoroot/dojo/dojo.js” ></script> 

在 Node.js 中,方法是類似的,需要一個 Node.js 可運行的模塊來引入 Dojo。例如,創建一個 bootstrap.js 文件,包含如下內容:

 global.dojoConfig = { 
    isDebug: true 
 }; 
 require('./dojo/dojo.js'); 

Node.js 中定義全局變量的方法和瀏覽器端略有區別,它是通過為 global 增加一個屬性來定義全局變量。隨后,通過 require 函數引入 Dojo,相當于 HTML 頁面中的 <script> 標簽。因此,在本質上,這個 bootstrap.js 文件就是包含配置信息的 Dojo。直接使用下面的代碼就可以在 Node 上運行 Dojo 了:

 node <bootroot>/bootstrap.js 

當然,這行命令什么也沒有干,只是運行了一下 Dojo。底下我們來看如何在 Dojo 里運行自己的 Dojo 程序。

2. 定義應用程序入口

上面提到了通過 dojoConfig 這個全局變量來配置 Dojo,除此之外,其中還可以定義自己的 package,每個 package 都可能是一個應用,或者一個類庫。所有的 package 都放在 packages 數組中:

 global.dojoConfig = { 
 isDebug: true,     
 packages: [{ 
         name: 'mynode'
         ,location: '../mynode'
     }] 
 }; 

在這里我們定義了一個名為 mynode 的 package,并指定了其位置。這是一個相對于 <dojoroot>/dojo/ 的位置。這樣,要執行這個 package,只要運行下面的命令:

 node <bootroot>/bootstrap.js load=mynode 

Dojo 通過 load 參數來獲得應該執行的 package,在這個 package 下的 main.js 模塊會被執行,下面將會介紹。

3. 執行應用程序

如前面所述,package 本身并沒有特別的地方,它就是一個文件夾。當僅指定一個 package,而非具體的模塊時,Dojo 就會自動執行其下的 main.js 文件。這個 main.js 模塊和普通的模塊本質上也沒有任何區別,但一般這個模塊中僅包含應用初始化的邏輯,從而能夠啟動應用的執行。

現在我們先來看一個簡單的“Hello world”的例子。我們不使用任何 Dojo 的模塊,而是只用 define 來定義一個自己的模塊,讓它打印“Hello world”。我們在 main.js 里放如下的內容:

 console.log(“Hello world”); 

這樣,當執行上面提到的命令:

 node <bootroot>/bootstrap.js load=mynode 

這樣,我們將會在命令行窗口看到輸出的“Hello world”。這里我們并沒有用任何的 Dojo 模塊,而是僅僅讓 Dojo 去尋找到 main.js 并執行它。那下面來看如何去依賴 Dojo 的模塊來實現自己的應用邏輯。

這個例子將使用 Dojo 對 Django 模板語言(DTL)模塊的實現來做字符串的轉換:

 define(['dojox/dtl', 'dojox/dtl/Context'], function(dtl, DtlContext){ 
     var template = new dtl.Template("Hello {{ place }}!"); 
     var context = new DtlContext({ 
         place: "World"
     }); 
     console.log(template.render(context)); 
     return null; 
 }); 

可以看到,通過使用 dojox.dtl 提供的功能,就能夠在服務器端將一個基于 DTL 模板的字符串轉換成 HTML。dojox.dtl 實現了完整的 DTL 語法,結合 Node.js 的 HTTP 模塊,就很容易創建一個自己的 Web Server,這在很大程度上得益于 Dojo 的 DTL 實現。

后記

有人曾預言 Node.js 將取代 PHP 成為最流行的服務器端語言,無論您信不信,Node.js 正在快速的演變和發展,并獲得越來越多的關注。基于 Node.js 的一些 Web Server 已經可以用于商業用途,例如 http://expressjs.com。這讓 JavaScript 這個簡潔而優雅的語言發揮散發出越來越大的魅力。而 Dojo 作為一個功能強大的 JavaScript 框架,在企業級應用中一直備受青睞,借助其對 Node.js 的完美支持,相信也能發揮出更大的作用。

文章出處:IBM developerWorks

 本文由用戶 fmms 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!