關於JavaScript模塊規範之CommonJS\AMD\CMD

本篇文章來自對文章《js模塊化編程之完全弄懂CommonJS和AMD/CMD!》的總結,大部分摘自文章原話,本人只是爲了學習方便作的筆記,以後有新的體會會及時補充。若有侵權,聯繫必刪,致敬前輩!javascript

在開始以前,先回答我:爲何模塊很重要?html

答:由於有了模塊,咱們就能夠更方便地使用別人的代碼,想要什麼功能,就加載什麼模塊。可是,這樣作有一個前提,那就是你們必須以一樣的方式編寫模塊,不然你有你的寫法,我有個人寫法,豈不是亂了套!前端

因而下面三個模塊規範出來了,這篇文章也出來了。提早說明一下,CommonJS規範的實現是node.js,AMD(Asynchronous Module Definition)規範的實現是require.js和curl.js,CMD規範的實現是Sea.js。java

JS中的模塊規範(CommonJS,AMD,CMD),若是你聽過js模塊化這個東西,那麼你就應該聽過或CommonJS或AMD甚至是CMD這些規範咯,我也聽過,但以前也真的是聽聽而已。 如今就看看吧,這些規範究竟是啥東西,幹嗎的。本文包括這三個規範的來源及對應的產物的原理。node

1、CommonJS規範

1.一開始你們都認爲JS是辣雞,沒什麼用,官方定義的API只能構建基於瀏覽器的應用程序,逗我呢,這太狹隘了吧(用了個高端詞,嘎嘎),CommonJS就按耐不住了,CommonJS API定義不少普通應用程序(主要指非瀏覽器的應用)使用的API,從而填補了這個空白。它的終極目標是提供一個相似Python,Ruby和Java標準庫。這樣的話,開發者可使用CommonJS API編寫應用程序,而後這些應用能夠運行在不一樣的JavaScript解釋器和不一樣的主機環境中。webpack

在兼容CommonJS的系統中,你可使用JavaScript開發如下程序:git

(1).服務器端JavaScript應用程序
(2).命令行工具
(3).圖形界面應用程序
(4).混合應用程序(如,Titanium或Adobe AIR)程序員

2009年,美國程序員Ryan Dahl創造了node.js項目,將javascript語言用於服務器端編程。這標誌"Javascript模塊化編程"正式誕生。由於老實說,在瀏覽器環境下,沒有模塊也不是特別大的問題,畢竟網頁程序的複雜性有限;可是在服務器端,必定要有模塊,與操做系統和其餘應用程序互動,不然根本無法編程。NodeJS是CommonJS規範的實現,webpack 也是以CommonJS的形式來書寫。github

node.js的模塊系統,就是參照CommonJS規範實現的。在CommonJS中,有一個全局性方法require(),用於加載模塊。假定有一個數學模塊math.js,就能夠像下面這樣加載。web

var math = require('math');

而後,就能夠調用模塊提供的方法:

  var math = require('math');

math.add(2,3); // 5

CommonJS定義的模塊分爲:{模塊引用(require)} {模塊定義(exports)} {模塊標識(module)}

require()用來引入外部模塊;exports對象用於導出當前模塊的方法或變量,惟一的導出口;module對象就表明模塊自己。

雖然說Node遵循CommonJS的規範,可是相比也是作了一些取捨,填了一些新東西的。

不過,說了CommonJS也說了Node,那麼我以爲也得先了解下NPM了。NPM做爲Node的包管理器,不是爲了幫助Node解決依賴包的安裝問題嘛,那它確定也要遵循CommonJS規範啦,它遵循包規範(仍是理論)的。CommonJS WIKI講了它的歷史,還介紹了modules和packages等。

下面講講commonJS的原理以及簡易實現:

一、原理
瀏覽器不兼容CommonJS的根本緣由,在於缺乏四個Node.js環境的變量。

module
exports
require
global

只要可以提供這四個變量,瀏覽器就能加載 CommonJS 模塊。

下面是一個簡單的示例。

var module = {
  exports: {}
};

(function(module, exports) {
  exports.multiply = function (n) { return n * 1000 };
}(module, module.exports))

var f = module.exports.multiply;
f(5) // 5000

上面代碼向一個當即執行函數提供 module 和 exports 兩個外部變量,模塊就放在這個當即執行函數裏面。模塊的輸出值放在 module.exports 之中,這樣就實現了模塊的加載。

2、AMD規範

基於commonJS規範的nodeJS出來之後,服務端的模塊概念已經造成,很天然地,你們就想要客戶端模塊。並且最好二者可以兼容,一個模塊不用修改,在服務器和瀏覽器均可以運行。可是,因爲一個重大的侷限,使得CommonJS規範不適用於瀏覽器環境。仍是上面的代碼,若是在瀏覽器中運行,會有一個很大的問題,你能看出來嗎?

var math = require('math');
math.add(2, 3);

第二行math.add(2, 3),在第一行require('math')以後運行,所以必須等math.js加載完成。也就是說,若是加載時間很長,整個應用就會停在那裏等。您會注意到 require 是同步的。

這對服務器端不是一個問題,由於全部的模塊都存放在本地硬盤,能夠同步加載完成,等待時間就是硬盤的讀取時間。可是,對於瀏覽器,這倒是一個大問題,由於模塊都放在服務器端,等待時間取決於網速的快慢,可能要等很長時間,瀏覽器處於"假死"狀態。

所以,瀏覽器端的模塊,不能採用"同步加載"(synchronous),只能採用"異步加載"(asynchronous)。這就是AMD規範誕生的背景。

CommonJS是主要爲了JS在後端的表現制定的,他是不適合前端的,AMD(異步模塊定義)出現了,它就主要爲前端JS的表現制定規範。

AMD是"Asynchronous Module Definition"的縮寫,意思就是"異步模塊定義"。它採用異步方式加載模塊,模塊的加載不影響它後面語句的運行。全部依賴這個模塊的語句,都定義在一個回調函數中,等到加載完成以後,這個回調函數纔會運行。

AMD也採用require()語句加載模塊,可是不一樣於CommonJS,它要求兩個參數:

require([module], callback);

第一個參數[module],是一個數組,裏面的成員就是要加載的模塊;第二個參數callback,則是加載成功以後的回調函數。若是將前面的代碼改寫成AMD形式,就是下面這樣:

require(['math'], function (math) {
    math.add(2, 3);
});

math.add()與math模塊加載不是同步的,瀏覽器不會發生假死。因此很顯然,AMD比較適合瀏覽器環境。目前,主要有兩個Javascript庫實現了AMD規範:require.js和curl.js。

Require.js主要提供define和require兩個方法來進行模塊化編程,前者用來定義模塊,後者用來調用模塊。RequireJS就是實現了AMD規範的呢。

3、CMD規範

大名遠揚的玉伯寫了seajs,就是遵循他提出的CMD規範,與AMD蠻相近的,不過用起來感受更加方便些,最重要的是中文版,應有盡有:seajs官方doc

define(function(require,exports,module){...});

前面說AMD,說RequireJS實現了AMD,CMD看起來與AMD好像呀,那RequireJS與SeaJS像不像呢?雖然CMD與AMD蠻像的,但區別仍是挺明顯的,官方非官方都有闡述和理解,我以爲吧,說的都挺好:

官方闡述SeaJS與RequireJS異同
SeaJS與RequireJS的最大異同(這個說的也挺好)

相關文章
相關標籤/搜索