1. 程式人生 > >詳解AMD、CommonJS和UMD模組化規範

詳解AMD、CommonJS和UMD模組化規範

開發的時候,我們經常會把某些功能封裝成可複用的模組。模組封裝了功能,並且對外暴露一個API。隨著Node.js的誕生和發展,JavaScript可以在服務端執行,同時客戶端應用也越來越流行,JavaScript界產生了對優秀和健壯模組系統的需求。在JavaScript中定義模組的規範也隨之產生。

這裡,將詳細介紹最常見的兩個定義模組的方法AMD和CommonJS,以及它們的結合UMD.

一、CommonJS

CommonJS模組可以說是當前最流行的模組定義規範。相比於AMD,它的工作效率更高、語法更簡單。一開始,CommonJS模組是JavaScript伺服器模組的規範。

基本原理

實現編譯程式碼,建立一個比原先更大的程式碼包,其中包含了所有應用執行所需的程式碼。

語法

const $ = require('jquery');       //將依賴載入到當前檔案

exports.init = function(){
    ...
};

特點

  • 沒有回撥函式
  • 同步載入,每個require語句會短暫阻塞程式碼的執行,知道模組載入完畢。不過這個載入不是通過網路載入,而是從記憶體或者檔案系統中載入,所以這個過程很快。
  • 程式碼簡單易懂
  • CommonJS模組不適合瀏覽器,因為瀏覽器的載入機制不支援同步。需要用打包工具把所有CommonJS模組打包成一個js檔案。

二、AMD——為瀏覽器設計的模組定義規範

AMD:Asynchronous Module Definition(非同步模組規範),最老的方式之一,專為瀏覽器而設計。

基本原理

用非同步載入技術來定義模組和依賴。提供define方法和require方法來定義和載入模組。

語法

define方法:

define(
    '模組id',
    ['依賴陣列'],
    function([依賴陣列]){     //工廠函式
        ...
    }
);

工廠函式內部包含了模組程式碼,工廠函式最後返回的結果,就是要暴露給其他模組的功能。

特點

  • 用AMD定義的模組至少需要一個工廠函式來暴露API給其他模組使用。
  • 依賴陣列中的依賴會被非同步載入。
  • 模組的載入通過客戶端(瀏覽器)向伺服器傳送HTTP請求來完成的,這個傳輸過程需要大量時間。
  • 可以定義具名模組,也可以定義匿名模組。具名模組通過開發者定義的名字載入,匿名模組隱式的以檔名載入。

require方法:

require(['jquery'],
    function($){        //回撥函式
    ...
    }
);

require方法與define方法相對應,用來顯示的載入模組。

特點

  • 可以在程式碼的任何地方使用require載入另一個模組。
  • require呼叫會發送一個請求來下載模組。
  • 非同步載入,只有在回撥函式裡才能獲取新拿到的API。

AMD模組載入流程示意圖
這裡寫圖片描述

UMD——通用模組規範

UMD:Universal Module Definition(通用模組規範)是由社群想出來的一種整合了CommonJS和AMD兩個模組定義規範的方法。

基本原理

用一個工廠函式來統一不同的模組定義規範。

原則

  • 所有定義模組的方法需要單獨傳入依賴
  • 所有定義模組的方法都需要返回一個物件,供其他模組使用

例如,利用UMD定義一個toggler模組:

(function (global, factory) {
    if (typeof exports === 'object' && typeof module !== undefined) { //檢查CommonJS是否可用
        module.exports = factory(require('jquery'));
    } else if (typeof define === 'function' && define.amd) {      //檢查AMD是否可用
        define('toggler', ['jquery', factory])
    } else {       //兩種都不能用,把模組新增到JavaScript的全域性名稱空間中。
        global.toggler = factory(global, factory);
    }
})(this, function ($) {
    function init() {

    }
    return {
        init: init
    }
});