AMD(中文版)

unknown_發表於2019-01-25

前言

本文是源倉庫裡的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, 會進行修改,謝謝。)

相關文章