AMD規範:簡單而優雅的動態載入JavaScript代碼

來源:互聯網
上載者:User

本文翻譯自http://www.sitepen.com/blog/2010/11/04/requirejsamd-module-forms/,並加入部分自己的解釋。

CommonJS 提出了一種用於同步或非同步動態載入JavaScript代碼的API規範,非常簡單卻很優雅,稱之為AMD(Modules/AsynchronousDefinition)。RequireJS和NodeJS的Nodules已經實現了這個API,而Dojo也將馬上完全支援(Dojo1.6)。規範本身非常簡單,甚至只包含了一個API: 
define([module-name?], [array-of-dependencies?], [module-factory-or-object]);

通過參數的排列組合,這個簡單的API可以從容應對各種各樣的應用情境,如下所述。

 匿名模組

在這種情境下,無需輸入模組名,即省略第一個參數,僅包含後兩個參數:相依模組的列表以及回呼函數,例如一個簡單的匿名模組可以用如下代碼定義:

define(["math"], function(math){ 
  return { 
    addTen: function(x){ 
      return math.add(x, 10); 
    } 
  }; 
}); 
在這裡,第一個參數表示依賴的模組列表,即math模組。一旦所有依賴的模組被載入完成,那麼第三個參數定義的回呼函數將被執行,相依模組的引用作為參數傳遞給回呼函數。

如例子中所示,如果模組名被省略不寫,那麼這是一個匿名模組。通過這種強大的方式,模組的原始碼與它的標識可以做到不相關。從而可以在不改變模組代碼的情況下移動源碼檔案的位置。這個技術遵循了基本的DRY(Don't
Repeat Yourself)原則,避免了模組標識的多次儲存(檔案名稱/路徑資訊不會在代碼中重複)。這不僅使得模組的開發變得更加容易,而且為模組的重用提供了極大的靈活性。

下面我們看如何從一個Web頁面載入這個模組。我們假設上面的模組儲存在檔案adder.js中。使用RequireJS,我們可以用下面方式來載入這個模組: 
<script src="require.js"></script> 
<script> 
require(["adder"], function(adder){ 
  // ready to use adder 
}); 
</script>  
一旦代碼被執行,RequireJS將會自動去調用adder模組所有的相依模組。載入完畢之後,我們就可以通過回呼函數的adder參數來使用前面定義的匿名模組。例子中可以看到,adder.js裡儲存的是定義的匿名模組,實際上我們可以用任何檔案/路徑來包含這個模組,為模組的重用提供了方便(Java中的檔案名稱/路徑和類名/包的必須一致性實際上就為類層級的重用造成了不便)。require函數用於載入任何一個模組,後面將多次使用。

對於匿名模組的使用有一些注意事項。比如每個檔案中只能包含一個匿名模組,而且匿名模組只能被載入器載入,即只能用require來載入。也可以這麼理解,實際上匿名模組並不是沒有名字,而是在使用時進行命名的模組,例子中就是adder。 

資料封裝:新的JSON-P

對於一些僅僅提供資料或者獨立方法(不依賴於其它模組的方法)的模組,可以簡單的用如下方式來定義: 
define({ 
  name:"some data" 
}); 
這個和JSON-P非常像,但是卻有一個顯著的優點:它使得JSON-P資料可以現在靜態檔案中,而並不需要動態回調過程。這也使得內容是可cache的,而且是CDN友好的。 

 封裝CommonJS模組

CommonJS也是一套RIA架構,其中的模組可以通過AMD來進行封裝,從而可以用define的方式很容易的進行非同步裝載,在這裡我們可以省略前2個參數,僅包含回呼函數,但回呼函數的第一個參數是require方法,第二個參數是exports對象,它定義了模組本身,回呼函數裡的require的使用將被自動進行動態載入。例如: 
define(function(require, exports){ 
//math是標準CommonJS模組: 
  var math = require("math"); 
  exports.addTen = function(x){ 
    return math.add(x, 10); 
  }; 
});  
需要注意這種形式要求模組載入器掃描require函數。require調用必須寫成require(“…”)的形式才能被正確識別從而正常工作。這在一些瀏覽器不能正常工作(例如默寫版本的Opera移動版,以及PS3)。當然,如果在部署前對代碼進行了build,這將完全不成問題。你也可以封裝CommonJS模組,並手動的指定依賴,這種方式使得我們也可以引用CommonJS變數,從而我們可以包含標準的require和exports變數: 
define(["require", "exports", "math"], function(require, exports){ 
// standard CommonJS module: 
  var math = require("math"); 
  exports.addTen = function(x){ 
    return math.add(x, 10); 
  }; 
});  
  

完整的模組定義

一個完整的模組定義包含了模組名,依賴,以及回呼函數。這種形式的優點是模組可以包含在另外的檔案中,或者可以用script標記載入的地址中。這是build工具自動產生的規範模式,使得多個依賴可以被打包在同一個檔案中,這種格式的例子如下: 
define("adder", ["math"], function(math){ 
  return { 
    addTen: function(x){ 
      return math.add(x, 10); 
    } 
  }; 
});

最後,我們來看有模組id,但沒有模組依賴的情況。這種情況用於你想指定模組id,但是這個模組不依賴於其它模組。這時的參數預設是“require”,“exports”和“module”。從而我們可以這樣建立adder模組。 
define("adder", function(require, exports){ 
  exports.addTen = function(x){ 
      return x + 10; 
  }; 
}); 
通過這種方式定義的模組可以被RequireJS載入,也可以作為其它模組的依賴被載入,或者直接用require()的形式載入。

綜上所述,這種API看似簡單,卻提供了一種極其靈活的方式來定義模組,適用於各種應用情境,從可被自由移動的匿名模組,到構建後的可被<script>標記載入的模組。當前RequireJS和Dojo實現了這套規範,而JavaScript的Web Server架構NodeJS的Nodules也實現了這個規範。

AMD規範:簡單而優雅的動態載入JavaScript代碼

本文翻譯自http://www.sitepen.com/blog/2010/11/04/requirejsamd-module-forms/,並加入部分自己的解釋。

CommonJS 提出了一種用於同步或非同步動態載入JavaScript代碼的API規範,非常簡單卻很優雅,稱之為AMD(Modules/AsynchronousDefinition)。RequireJS和NodeJS的Nodules已經實現了這個API,而Dojo也將馬上完全支援(Dojo1.6)。規範本身非常簡單,甚至只包含了一個API: 
define([module-name?], [array-of-dependencies?], [module-factory-or-object]);

通過參數的排列組合,這個簡單的API可以從容應對各種各樣的應用情境,如下所述。

 匿名模組

在這種情境下,無需輸入模組名,即省略第一個參數,僅包含後兩個參數:相依模組的列表以及回呼函數,例如一個簡單的匿名模組可以用如下代碼定義:

define(["math"], function(math){ 
  return { 
    addTen: function(x){ 
      return math.add(x, 10); 
    } 
  }; 
}); 
在這裡,第一個參數表示依賴的模組列表,即math模組。一旦所有依賴的模組被載入完成,那麼第三個參數定義的回呼函數將被執行,相依模組的引用作為參數傳遞給回呼函數。

如例子中所示,如果模組名被省略不寫,那麼這是一個匿名模組。通過這種強大的方式,模組的原始碼與它的標識可以做到不相關。從而可以在不改變模組代碼的情況下移動源碼檔案的位置。這個技術遵循了基本的DRY(Don't
Repeat Yourself)原則,避免了模組標識的多次儲存(檔案名稱/路徑資訊不會在代碼中重複)。這不僅使得模組的開發變得更加容易,而且為模組的重用提供了極大的靈活性。

下面我們看如何從一個Web頁面載入這個模組。我們假設上面的模組儲存在檔案adder.js中。使用RequireJS,我們可以用下面方式來載入這個模組: 
<script src="require.js"></script> 
<script> 
require(["adder"], function(adder){ 
  // ready to use adder 
}); 
</script>  
一旦代碼被執行,RequireJS將會自動去調用adder模組所有的相依模組。載入完畢之後,我們就可以通過回呼函數的adder參數來使用前面定義的匿名模組。例子中可以看到,adder.js裡儲存的是定義的匿名模組,實際上我們可以用任何檔案/路徑來包含這個模組,為模組的重用提供了方便(Java中的檔案名稱/路徑和類名/包的必須一致性實際上就為類層級的重用造成了不便)。require函數用於載入任何一個模組,後面將多次使用。

對於匿名模組的使用有一些注意事項。比如每個檔案中只能包含一個匿名模組,而且匿名模組只能被載入器載入,即只能用require來載入。也可以這麼理解,實際上匿名模組並不是沒有名字,而是在使用時進行命名的模組,例子中就是adder。 

資料封裝:新的JSON-P

對於一些僅僅提供資料或者獨立方法(不依賴於其它模組的方法)的模組,可以簡單的用如下方式來定義: 
define({ 
  name:"some data" 
}); 
這個和JSON-P非常像,但是卻有一個顯著的優點:它使得JSON-P資料可以現在靜態檔案中,而並不需要動態回調過程。這也使得內容是可cache的,而且是CDN友好的。 

 封裝CommonJS模組

CommonJS也是一套RIA架構,其中的模組可以通過AMD來進行封裝,從而可以用define的方式很容易的進行非同步裝載,在這裡我們可以省略前2個參數,僅包含回呼函數,但回呼函數的第一個參數是require方法,第二個參數是exports對象,它定義了模組本身,回呼函數裡的require的使用將被自動進行動態載入。例如: 
define(function(require, exports){ 
//math是標準CommonJS模組: 
  var math = require("math"); 
  exports.addTen = function(x){ 
    return math.add(x, 10); 
  }; 
});  
需要注意這種形式要求模組載入器掃描require函數。require調用必須寫成require(“…”)的形式才能被正確識別從而正常工作。這在一些瀏覽器不能正常工作(例如默寫版本的Opera移動版,以及PS3)。當然,如果在部署前對代碼進行了build,這將完全不成問題。你也可以封裝CommonJS模組,並手動的指定依賴,這種方式使得我們也可以引用CommonJS變數,從而我們可以包含標準的require和exports變數: 
define(["require", "exports", "math"], function(require, exports){ 
// standard CommonJS module: 
  var math = require("math"); 
  exports.addTen = function(x){ 
    return math.add(x, 10); 
  }; 
});  
  

完整的模組定義

一個完整的模組定義包含了模組名,依賴,以及回呼函數。這種形式的優點是模組可以包含在另外的檔案中,或者可以用script標記載入的地址中。這是build工具自動產生的規範模式,使得多個依賴可以被打包在同一個檔案中,這種格式的例子如下: 
define("adder", ["math"], function(math){ 
  return { 
    addTen: function(x){ 
      return math.add(x, 10); 
    } 
  }; 
});

最後,我們來看有模組id,但沒有模組依賴的情況。這種情況用於你想指定模組id,但是這個模組不依賴於其它模組。這時的參數預設是“require”,“exports”和“module”。從而我們可以這樣建立adder模組。 
define("adder", function(require, exports){ 
  exports.addTen = function(x){ 
      return x + 10; 
  }; 
}); 
通過這種方式定義的模組可以被RequireJS載入,也可以作為其它模組的依賴被載入,或者直接用require()的形式載入。

綜上所述,這種API看似簡單,卻提供了一種極其靈活的方式來定義模組,適用於各種應用情境,從可被自由移動的匿名模組,到構建後的可被<script>標記載入的模組。當前RequireJS和Dojo實現了這套規範,而JavaScript的Web Server架構NodeJS的Nodules也實現了這個規範。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.