理解dojo.require機制

轉自:http://blog.csdn.net/dojotoolkit/article/details/5935844javascript

Dojo 提供了一個很是強大的javascript控件庫. 在使用dojo以前,用戶基本上不須要具有任何基礎知識. 你能夠用script遠程連接到dojo(dojo.js), 也能夠把dojo.js下載到本地並用script標籤加載.html

若是你不太瞭解dojo, 能夠參考一下以下資料:java

大致上,dojo.js和jquery.js 或者 prototype js, 裏面有不少開發web應用的經常使用的特性: 包括:jquery

  • JavaScript Language Helpers
  • Object 工具
  • Array 工具
  • DOM 操做
  • 標準的事件機制
  • Ajax & 跨域請
  • JSON 工具
  • 簡單特效
  • 瀏覽器兼容

 

不只如此, dojo還有不少其餘javascript庫(jquery, ext等等)所不具備的功能. 其中一個很重要的功能就是模塊化的機制 - 模塊系統(dojo.require() ). JavaScript 和 瀏覽器自己以及其餘的javascript庫並不支持這種特性, dojo很好的解決了這種問題.web

模塊系統

dojo.require('my.module') 用於加載javascript文件, 功能相似於script標籤的做用.跨域

假設你有一個本地的開發環境,目錄結構以下:(http://localhost:8888 .)瀏覽器

file1

index.html 是一個包含 dojo.js 簡單頁面 .緩存

 

<!DOCTYPE html>
<html lang=」en」>
<head>
<meta charset=」utf-8″ />
<title>Dojo</title>
</head>
<body>
<script src=」dojo/dojo.js」></script> 
</body>
</html>
 

假設咱們要用Flickr API獲取數據, 這時候,咱們就要用到跨域請求, 可是這些功能模塊並非在dojo base庫裏面, 咱們須要另外加載所需的dojo模塊:安全

 

<!DOCTYPE html>
<html lang=」en」>
<head>
<meta charset=」utf-8″ />
<title>Dojo</title>
</head>
<body>
<script src=」/dojo/dojo.js」></script>
<script src=」/dojo/io/script.js」></script> 
</body>
</html>  
 

這裏咱們能夠用script標籤解決這種問題, 一樣還有另一種方式, 這種方式體現了模塊系統的宗旨: 咱們用dojo.require() 加載 dojo.io.script  app

 

<!DOCTYPE html>
<html lang=」en」>
<head>
<meta charset=」utf-8″ />
<title>Dojo</title>
</head>
<body>
<script src=」/dojo/dojo.js」></script>
<script>
dojo.require(」dojo.io.script」); 
//Note: do not include the .js
</script>
</body>
</html>

 

經過 dojo.require() 咱們得到了一個模塊系統, 它提供了一系列咱們開發複雜web2.0頁面所須要的組件. 接下來的內容咱們會着重介紹模塊系統的特性:

  • 緩存管理
  • 命名空間管理
  • 路徑管理
  • 依賴管理

首先, dojo.require()會避免重複加載, 若是script腳本被瀏覽器緩存了, dojo會調用緩存的資源從而避免沒必要要的http請求, 事實上,你能夠隨便調用 dojo.require(), 無論調用了多少 dojo.require(), dojo都會保證一樣的模塊只會被加載一次.

 

咱們也能夠建立本身的模塊. 讓咱們回到Flickr API的例子, 咱們要開發一個用Flickr數據的大型web應用, 咱們須要能很好的組織和管理這些javascript代碼. 歸根結底,咱們須要建立名爲flickrApp的命名空間用於保存全部該應用的邏輯功能. 爲了達到這個目的, 咱們更新原有的目錄結構, 建立一個flickrApp.js文件:

file2

flickrApp.js看起來彷佛僅僅是一個js文件, 但若是你用dojo的眼光來看他, 你會發現他其實應該是一個模塊, 爲了讓dojo識別他是這個模塊, 咱們用 dojo.provide() 方法初始化這個js文件,將其變爲一個dojo的模塊. 咱們加入以下代碼到 flickrApp.js 文件中:

[javascript]  view plain copy
 
  1. dojo.provide(」flickrApp 「); //similar to doing flickrApp = {};  

 

dojo.provide() 建立了一個以你傳入的字符串(flickrApp )命名的對象結構(名字空間), 咱們這裏是建立了一個名爲flickrApp的對象, 該對象建立後, 咱們即可以像定義該對象的各個屬性同樣來定義該應用( flickrApp ) 的各個方面, 下面是 flickrApp.js 一個例子:

[javascript]  view plain copy
 
  1. dojo.provide(」flickrApp」);  
  2. //start creating the application logic for my flickr app  
  3. flickrApp.getData = function(){};  
如今咱們能夠用  dojo.require() 來加載咱們自定義的模塊到HTML頁面上:
 
<!DOCTYPE html>
<html lang=」en」>
<head>
<meta charset=」utf-8″ />
<title>Dojo</title>
</head>
<body>
<script src=」/dojo/dojo.js」></script>
<script>
dojo.require(」dojo.io.script」);
dojo.require(」flickrApp」); 
</script>
</body>
</html>
 

問題來了, dojo是怎麼知道flickrApp.js模塊的文件系統中存放的位置的呢? 答案就是dojo的路徑管理機制, dojo會根據你傳入 dojo.provide() 的字符串來定位該模塊的位置,基準點是dojo.js的上一級目錄, 好比dojo.js在 http://localhost:8888/dojo/dojo.js,因此dojo會在 http://localhost:8888/這個目錄級別(dojo.js的上一級)來定位全部的模塊。 爲了說明這個問題, 咱們如今來再一次改變例子的文件結構,使其看起來 更加具備組織性,以下:

file3

此時,全部的應用相關的代碼都在flickrApp這個目錄(名字空間)下,在這個目錄下,咱們能夠更進一步將該應用切分紅不一樣的模塊。第一個模塊就是data.js模塊,包含獲取 Flickr數據的邏輯功能,以及跨域,返回數據等等功能。基於這個改變,咱們須要在data.js裏面加入 dojo.provide()語句來告訴他新的目錄結構的改變,以下(data.js ):

 

[javascript]  view plain copy
 
  1. //below is similar to doing var flickrApp = {}; flickrApp.data = {};  
  2. dojo.provide(」flickrApp.data 「);  
  3. // Note: do not include the .js  
  4. flickrApp.data.getData = function(){};  

就像咱們以前所說的,dojo會從dojo.js(http://localhost:8888/dojo/dojo.js )的上一級目錄來開始定位各個模塊,因此這裏dojo定位咱們的data.js 模塊的路徑爲http://localhost:8888/flickrApp/data.js。此時,咱們的HTML代碼也要作相應的改動:

 

<!DOCTYPE html>
<html lang=」en」>
<head>
<meta charset=」utf-8″ />
<title>Dojo</title>
</head>
<body>
<script src=」/dojo/dojo.js」></script>
<script>
dojo.require(」dojo.io.script」);
dojo.require(」flickrApp.data 「);
</script>
</body>
</html>
 

好了,到此爲止,咱們來想想,這樣作真的有必要嗎,咱們爲何不能不要藉助這種模塊系統,而僅僅是把應用程序全部的邏輯功能都放在一個javascript文件中呢? 固然能夠。可是dojo實現模塊系統的目的在於更好更方便的管理代碼,也便於用工具壓縮優化代碼。

接下來咱們討論一下最重要的部分:依賴管理.

模塊能夠包含對其餘模塊的引用,即在模塊中能夠require()其餘的模塊, dojo會幫你管理這些模塊,讓咱們回到咱們HTML頁面:

 

<!DOCTYPE html>
<html lang=」en」>
<head>
<meta charset=」utf-8″ />
<title>Dojo</title>
</head>
<body>
<script src=」/dojo/dojo.js」></script>
<script>
dojo.require(」dojo.io.script」); 
dojo.require(」flickrApp.data」);
</script>
</body>
</html>
 

咱們能夠看到,這裏咱們會在HTML頁面上require 這個dojo.io.script.js模塊, 事實上咱們能夠把這個require()語句放到 data.js模塊裏面,其實這裏 data.js模塊是依賴於 dojo.io.script.js模塊的,dojo會管理這個依賴關係,因此此時 data.js模塊以下:

[javascript]  view plain copy
 
  1. dojo.provide(」flickrApp.data」);  
  2. dojo.require(」dojo.io.script」);  
  3. // Note: dojo.require() should be used after dojo.provide()  
  4. flickrApp.data.getData = function(){};  

此時,咱們的HTML頁面就只須要包含一個 require() 語句 (data.js模塊) .

 
<!DOCTYPE html>
<html lang=」en」>
<head>
<meta charset=」utf-8″ />
<title>Dojo</title>
</head>
<body>
<script src=」/dojo/dojo.js」></script>
<script>
dojo.require(」flickrApp.data」);
</script> 
</body>
</html>
 

dojo會管理這些依賴關係,確保data.js依賴於 dojo.io.script.js。

更有甚者,依賴管理還須要一個響應通知,即當全部依賴的模塊都被加載完成後的一個響應通知。這件事情能夠用dojo.ready()這個函數來實現, dojo.ready()將會註冊一個函數,這個函數會在全部的DOM節點加載完成,而且全部模塊及其的依賴模塊都加載和解析完成時 被調用。用法以下:

 

 

<!DOCTYPE html>
<html lang=」en」>
<head>
<meta charset=」utf-8″ />
<title>Dojo</title>
</head>
<body>
<script src=」/dojo/dojo.js」></script>
<script>
dojo.require(」flickrApp.data」);
dojo.ready(function(){ 
// Note that dojo.ready() is a shortcut for dojo.addOnLoad() added in Dojo 1.4
// Run code from data.js and all its dependencies safely
}); 
</script>
</body>
</html>
 

dojo.ready() 能夠用在任什麼時候間,任何地方,甚至是dojo.ready()的callback方法裏面,好比 :

[javascript]  view plain copy
 
  1. dojo.require(」some.module」);  
  2. dojo.ready(function(){  
  3. //run code from some.module.js and all its dependencies safely  
  4. dojo.require(’some.other.module’);  
  5. dojo.ready(function(){  
  6. //run code from some.other.module.js and all its dependencies safely  
  7. });  
  8. });  

 

 

就像前面提到的,當用到dojo的 require()時,dojo會從dojo.js的上一級目錄開始查找,好比require('some.other.module')會從 some/other/module.js開始查找:

 

file4

其實dojo也提供了咱們定義dojo的默認查找路徑的方式,咱們再更新一下咱們應用程序的結構,以下:

file5

能夠看到,咱們的模塊 - some.other.module.js已經在dojo默認的模塊查找路徑以外了,咱們要告訴dojo這個結構的變化就要用到 dojo.registerModulePath():

 

 

<!DOCTYPE html>
<html lang=」en」>
<head>
<meta charset=」utf-8″ />
<title>Dojo</title>
</head>
<body>
<script src=」/js/dojo1.4.1/dojo.js」></script>
<script>
dojo.registerModulePath(」some」, 「../../some/」); 
dojo.require(」some.other.module」);
</script>
</body>
</html>
 

經過dojo.registerModulePath("some", "../../some/") 語句,dojo便知道這個用戶自定義的模塊的位置,這裏,咱們告訴dojo咱們的自定義模塊some是在dojo.js的上兩級(../../some ),這個時候,dojo便知道了如何去解析這個名字空間(some.other.module )並加載some.other.module.js文件了。此時此刻,dojo便能識別全部在「../../some/ 」路徑下的自定義模塊。之因此須要這樣作的緣由主要是安全問題,瀏覽器是不支持javascript訪問文件系統的。 若是你對 djConfig 比較瞭解的話,你會發現其實這個對象也能夠用來作「dojo.registerModulePath() 」的工做:

 

<!DOCTYPE html>
<html lang=」en」>
<head>
<meta charset=」utf-8″ />
<title>Dojo</title>
</head>
<body>
<script type=」text/javascript」>
var djConfig = {modulePaths:{」some」:」../../some/」}}; 
</script>
<script src=」/dojo/dojo1.4.1/dojo.js」></script>
<script>
dojo.require(」some.other.module」);
</script>
</body>
</html>
 

其實dojo關於模塊系統的內容還有不少,這裏咱們主要是基於本地的dojo,其實dojo還能夠以跨域的方式加載(從AOL或者Google CDN),因此模塊系統也會去支持這種特性。模塊系統的底層實現是基於XHR去請求模塊內容的,這些在你用dojo的CDN版本是會改變,這時模塊系統會轉換到跨域的方式(基於script元素)。

Dojo以外

其實這些模塊系統的想法也能夠在沒有dojo的狀況下使用。 YUI3.0也有一個相似的實現,一樣,也有一些針對模塊系統的想法而專門實現的獨立的控件庫,其中之一就是RequireJS ,他是基於dojo實現的。有興趣不妨下載下來研究一下。

相關文章
相關標籤/搜索