前端模塊化進程,commonJS,AMD,CMD對比

commonJS規範

隨着前端技術的不斷髮展,項目愈來愈大,愈來愈很差管理,多人開發越來讓開發者頭疼,因而出現了命名空間,這沒有辦法的辦法,可是全部變量都是全局的話,管理很是混亂,並且在Node 出現前,javascript 在服務器端基本沒有市場,通過javascript 不斷努力,社區爲 javascript 制定了相應的規範。其中 commonJS 規範的提出算是最爲重要的里程碑。
commonJS對模塊的引用很是簡單,主要分爲模塊引用、模塊定義和模塊標示3部分javascript

1.模塊定義

在模塊中,上下文提供了 require() 方法來引入外來模塊,引入對應的功能。上下文還提供了 exports 對象,用來導出當前模塊的方法或變量。上下文還提供了一個module對象,它表明模塊自己,而 exports 是 module 的屬性。在node中一個文件就是一個模塊,將方法掛載在exports上做爲屬性便可定義導出方式。html

// math.js
exports.add = function () {
    var sum = 0,
        i = 0,
        args = arguments,
        l = args.length;
    while (i < l) {
        sum += args[i];
        i++
    }
    return sum;
}

2.模塊引用

在commonJS規範中,存在 require() 方法,這個方法接受模塊標示,以此引入一個模塊的API到當前的上下文中。
模塊引入的實例代碼前端

var math = require('math');

3.模塊標示

模塊標示其實就是傳遞給require()的參數,必須符合小駝峯命名的字符串,或者以.,..開頭的相對路徑,或者絕對路徑。java

commonJS 和 AMD

CommonJS是主要爲了JS在後端的表現制定的,他是不適合前端的,爲何這麼說呢?
這須要分析一下瀏覽器端的js和服務器端js都主要作了哪些事,有什麼不一樣了:node

服務器端 瀏覽器js
加載時從磁盤中加載 加載時須要經過網絡加載
相同的代碼須要屢次執行 代碼須要從一個服務器端分發到多個客戶端執行
CPU和內存資源是瓶頸 帶寬是瓶頸

commonJS在服務器端運行徹底沒有問題的,由於全部資源都在服務器端的磁盤裏,加載速度很快。可是在瀏覽器端由於網速的限制,加載資源須要時間,會阻塞代碼的運行,而AMD(異步模塊定義)的出現,能夠異。它的模塊定義以下:jquery

define(id?, dependencies?, factory);

它的模塊id和依賴都是可選的,而factory函數的內容就是實際代碼內容,假設一個模塊不依賴任何一個模塊後端

//math.js
define(function () {
    var math = {};
    math.add = function (arr) {
        for(var i = 0, sum = 0; i < arr.length; i++) {
            sum += arr[i];
        }
        return sum;
    }
    math.muti = function (arr) {
        for(var i = 0, sum = 0; i < arr.length; i++) {
            sum *= arr[i];
        }
        return sum;
    }
})

引用的時候這樣寫瀏覽器

//main.js
define(['math', function(math) {
    var arr = [1, 10, 20],
        sum = math.add(arr);
    console.log(sum);   //31
}]

固然這是原理,你們明白了以後,對於入門者,估計仍是不知道怎麼去用,那麼我就幫人幫到底(會用的繞過)。服務器

  1. 引入一個requirejs
<script src="js/require.js"></script>

若是以爲以爲這個文件加載也會堵塞 js 的話就把他放在代碼的底部,而後這樣寫網絡

<script src="js/require.js" defer async="true" ></script>

其中defer是爲了兼容IE瀏覽器。加載完requirejs以後,怎麼加載咱們本身的js呢

2.加載咱們本身的js

<script src="js/require.js" data-main="path/main"></script>
// main.js
// 首先用config()指定各模塊路徑和引用名
require.config({
  baseUrl: "js/lib",
  paths: {
    "jquery": "jquery.min",  //實際路徑爲js/lib/jquery.min.js
    "underscore": "underscore.min",
  }
});
// 執行基本操做
require(["jquery","underscore"],function($,_){
  // some code here
});

data-main 屬性裏面的就是咱們本身的入口文件了,因爲 requirejs 默認加載 js 文件的,因此 後綴 js 能夠省略。OK,下面就能夠快樂的寫模塊了。

CMD規範

CMD規範由國內的玉伯大神指出。是另外一種js模塊化方案,它與AMD很相似,不一樣點在於:AMD 推崇依賴前置、提早執行,CMD推崇依賴就近、延遲執行。

/** AMD寫法 **/
define(["a", "b", "c", "d", "e", "f"], function(a, b, c, d, e, f) { 
     // 等於在最前面聲明並初始化了要用到的全部模塊
    a.doSomething();
    if (false) {
        // 即使沒用到某個模塊 b,但 b 仍是提早執行了
        b.doSomething()
    } 
});

/** CMD寫法 **/
define(function(require, exports, module) {
    var a = require('./a'); //在須要時申明
    a.doSomething();
    if (false) {
        var b = require('./b');
        b.doSomething();
    }
});

/** sea.js **/
// 定義模塊 math.js
define(function(require, exports, module) {
    var $ = require('jquery.js');
    var add = function(a,b){
        return a+b;
    }
    exports.add = add;
});

require, exports 和 module 經過形參傳遞給模塊,在須要依賴模塊時,隨時引入,能夠看出,與 AMD 規範相比,CMD 規範更加接近 node 對 commonJS規範的定義。

兼容多種模塊規範

技術在發展,優秀的開源項目也在不斷更新,好比jquery,underscore。它們很快出了兼容不一樣規範的版本,那麼他們是怎麼作到的,是寫好幾套符合不一樣規範的代碼麼,固然不是。那麼咱們怎麼寫出像他們那樣兼容不一樣規範的代碼呢,很簡單,我給出一個例子:

//hello.js
;(function(name, definition){
    //檢測上下文環境是否爲 AMD 或 CMD
    var hasDefine = typeof define === 'function',
        hasExports = typeof module !== 'undefined' && module.exports;
    if (hasDefine) {
        //AMD 環境或 CMD 環境
        define(definition);
    } else if (hasExports) {
        // 定義爲普通的node模塊
        module.exports = definition();
    } else {
        //將模塊的執行結果掛在 window 變量中,在瀏覽器中 this 指向 window 對象
        this[name] = definition();
    }
})('hello', function() {
    //代碼主體
    var hello = function () {};
    return hello;
})
相關文章
相關標籤/搜索