- 原文地址: github.com/amdjs/amdjs…)
- 原文作者: James Burke
前言
本文是源倉庫裡的AMD文件的一份拷貝,放在這裡是用來維護歷史連結。文中任何與源倉庫裡的文件不一致之處,以源倉庫裡的文件為準。
非同步模組定義規範(AMD)制定了定義模組的規則, 這樣模組和模組的依賴可以被非同步載入。這和瀏覽器的非同步載入模組的環境剛好適應(瀏覽器同步載入模組會導致效能、可用性、除錯和跨域訪問等問題。)
此AMD與科技公司AMD及其製造的AMD處理器無關。
API說明
define()函式
本規範只定義了一個函式”define”, 它是全域性變數。函式的描述為:
define(id?, dependencies?, factory)複製程式碼
id
第一個引數, id是個字串。它指的是定義模組的名字, 這個引數是可選的。如果沒有提供該引數, 模組的名字應該預設為模組載入器請求的指定指令碼的名字。如果提供了該引數, 模組名必須是”頂級” 的和絕對的(不允許相對名字)。
模組名的格式
模組名用來唯一標識定義中模組, 它們同樣在依賴陣列中使用。AMD的模組名規範是CommonJS模組名規範的超集。引用如下:
- 模組名是由一個或多個單詞以正斜槓為分隔符拼接成的字串
- 單詞須為駝峰形式,或者”.”, “..”
- 模組名不允許副檔名的形式, 如”.js”
- 模組名可以為”相對的”或”頂級的”。如果首字元為”.” 或 “..”則為”相對的”模組名
- 頂級的模組名從根名稱空間的概念模組解析
- 相對的模組名從”require”書寫和呼叫的模組解析
上文引用的CommonJS模組id屬性常被用於JavaScript模組。
相對模組名解析示例:
- 如果模組
"a/b/c"
請求"../d"
, 則解析為"a/d"
- 如果模組
"a/b/c"
請求"./e"
, 則解析為"a/b/e"
如果AMD的實現載入器外掛(Loader-Plugins), 則”!”符號用於分隔載入器外掛模組名和外掛資源名。由於外掛資源名可以非常自由地命名,大多數字符都允許在外掛資源名使用。
(譯註: 關於Loader-Plugins)
依賴
-
第二個引數, dependdencies是個定義中模組所依賴模組的陣列。依賴模組必須根據模組的工廠方法優先順序執行,並且執行的結果應該按照依賴陣列中的位置順序以引數的形式傳入(定義中模組的)工廠方法中。
依賴的模組名如果是相對的,應該解析為相對定義中的模組。換句話來說,相對名解析為相對於模組的名字,並非相對於尋找該模組的名字的路徑。 -
本規範定義了三種特殊的依賴關鍵字。如果”require”, “exports”, 或”module”出現在依賴列表中, 引數應該按照CommonJS模組規範自由變數去解析。
-
依賴引數是可選的,如果忽略此引數,它應該預設為[“require”, “exports”, “module”]。然而,如果工廠方法的形參個數小於3,載入器會選擇以函式指定的引數個數呼叫工廠方法。
工廠方法
第三個引數, factory, 為模組初始化要執行的函式或物件。如果為函式, 它應該只被執行一次。如果是物件,此物件應該為模組的輸出值。
如果工廠方法返回一個值(物件, 函式, 或任意強制型別轉換為true的值), 應該為設定為模組的輸出值。
簡單的CommonJS轉換
- 如果依賴性引數被忽略,模組載入器可以選擇掃描工廠方法中的require語句獲得依賴性(字面量形參為require(“module-id”))。 第一個引數必須字面量為require從而使此機制正常工作。
- 在某些情況下,因為指令碼大小的限制或函式不支援toString方法(Opera Mobile是已知的不支援函式的toString方法),模組載入器可以選擇掃描不掃描依賴性。
- 如果有依賴引數, 模組載入器不應該在工廠方法中掃描依賴性。
define.amd屬性
-
為了清晰的標識全域性函式(為瀏覽器載入script必須的)遵從AMD程式設計介面, 任何全域性函式應該有一個”amd”的屬性, 它的值為一個物件。這樣可以防止與現有的定義了define函式但不遵從AMD程式設計介面的程式碼相沖突。
-
當前,define.amd物件的屬性沒有包含在本規範中。實現本規範的作者,可以用它通知超出本規範程式設計介面基本實現的額外能力。
-
define.amd的存在表明函式遵循本規範。如果有另外一個版本的程式設計介面,那麼應該定義另外一個屬性,如define.amd2, 表明實現只遵循該版本的程式設計介面。
一個如果定義同一個環境中允許多次載入同一個版本的模組的實現:
define.amd = {
multiversion: true
}複製程式碼
最簡單的定義:
define.amd = {}複製程式碼
一次輸出多個模組
在一個指令碼中可以使用多次define呼叫。這些define呼叫的順序不應該是重要的。早一些的模組定義中所指定的依賴,可以在同一指令碼中晚一些定義。模組載入器負責延遲載入未接解決的依賴,直到全部指令碼載入完畢,防止沒必要的請求。
例子
使用require和exports
建立一個名為”alpha”的模組,使用了require, exports和名為”beta”的模組:
define("alpha", ["require", "exports", "module"], function (require, exports, beta) {
exports.verb = function () {
return beta.verb()
// Or:
return requre("beta").verb()
}
})複製程式碼
一個返回物件的匿名模組:
define(["alpha"], function (alpha) {
return {
verb: function () {
return alpha.verb() + 2
}
}
})複製程式碼
一個沒有依賴性的模組可以直接定義物件:
define({
add: function (x, y) {
return x + y
}
})複製程式碼
一個使用了簡單CommonJS轉換的模組定義:
define(function(require, exports, module) {
var a = require("a")
b = require("b")
exports.action = function () {}
})複製程式碼
全域性變數
本規範保留全域性變數”define”以用來實現本規範。包額外資訊非同步定義程式設計介面是未將來的CommonJS API保留的。模組載入器不應在此函式新增額外的方法或屬性。
本規範保留全域性變數”require”被模組載入器使用。模組載入器可以在合適的情況下自由地使用該全域性變數。它可以使用這個變數或新增任何屬性以完成模組載入器的特定功能。它同樣也可以選擇完全不使用”require”。
使用注意
為了使靜態分析工具(如果build工具)可以正常工作,推薦使用字面上形如的”define(…)”。
與CommonJS的關係
一個關於本API的wiki開始在CommonJS wiki中建立了,作為中轉的格式,模組中轉。但是為了包含模組定義介面,隨著時間而不斷改變。在CommonJS列表中關於推薦本API作為模組定義API尚未達成一致。本API被轉移到它自己的wiki和討論組中。
AMD可以作為CommonJS模組一箇中轉的版本只要CommonJS沒有被用來同步的require呼叫。使用同步require呼叫的CommonJS程式碼可以被轉換為使用回撥風格的AMD模組載入器。
感言
本人只是一個搬運工, 如有不符之處請指出,寫部落格的作用只是為了複習基礎(好記性不如爛筆頭)。這是寫的第一篇博文,後續會有各種基礎的博文,如果有需求的可以關注。
(不符之處請發郵箱: unknown_xxx@163.com, 會進行修改,謝謝。)