AMD規範學習筆記

背景

NodeJS的一套比較簡潔 Moudles 規範, 使得在服務器端的模塊化變得更加簡單。很長一段時間,不少公司或者項目都有本身的一套模塊化機制, 卻未能造成一套統一的標準, NodeJS的Moudles規範若是運用在瀏覽器端會存在一些問題,如javascript

  1. 服務器端JS模塊文件就在本地,瀏覽器端則須要經過網絡請求
  2. 服務器端能夠很容易的實現同步或異步請求模塊,瀏覽器端代價會比較大

採用XHR的方式實現同步請求模塊,存在明顯的跨域缺陷,而使用script的方式,默認是異步的。 在這樣的背景下, CommonJS的Modules/Wrappings、AMD、CMD等規範應時而生。html

Modules/Wrappings 規範的約定以下,更多請參考:http://wiki.commonjs.org/wiki/Modules/Wrappings前端

  1. 使用modules.declare定義模塊
  2. declare 只接受一個參數,類型能夠是函數也能夠是object,參數又稱爲module factory
  3. 若是factory爲function,三個參數分別爲require、exports、module,factory使用返回值或exports導出模塊API
  4. factory若是是對象類型,則將該對象做爲模塊輸出

A basic wrapped module:java

module.declare(function(require, exports, module){
    exports.foo = "bar";
});

AMD 規範

AMD:全稱爲異步模塊定義, 是專門爲瀏覽器中JavaScript環境設計的規範. 規範自己很是簡單, 歸納以下:jquery

define(id?, dependencies?, factory);git

  id: 模塊名github

  dependencies: 依賴的模塊,若是缺省,默認爲 ["require", "exports", "module"]正則表達式

  factory: 模塊工廠,經過排列組合這種模塊定義能知足不少場景的需求api

AMD在定義本身的Module規範的同時,也簡單兼容了CommonJS的Modules/Wrappings。跨域

匿名模塊與具名模塊

define(["beta"], function (beta) {
    exports.verb = function() {
           return beta.verb();
       }
});
 
define('alpha', ["beta"], function (beta) {
    exports.verb = function() {
           return beta.verb();
       }
});

匿名模塊也帶來一些好處,如減小維護成本,使得模塊的源代碼與它的標識分離。從而實如今不改變模塊代碼的狀況下移動源碼文件的位置等。

Simplified CommonJS wrapping

define(function(require, exports, module){
    var query = require("query");
    var on = require("on");
    ...
});

AMD模塊加載器將會掃描該工廠函數的require調用,並自動的在運行該工廠方法以前加載他們, 也是和CMD規範的重要區別, 不少人在討論到AMD、CMD上都會探討這個問題,有許多爭議, 不過這點也正是體現了AMD規範的核心:模塊依賴必須在真正執行具體的factory方法前解決。

RequireJS是目前最流行的AMD加載器,從代碼中能夠看出,爲了支持CommonJS Wrapping, define會解析工廠函數的FunctionBody,去掉註釋,並將require的模塊匹配出來, 加到dependencies數組中。

var commentRegExp = /(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg,
    cjsRequireRegExp = /[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g;
 
if (!deps && isFunction(callback)) {
    deps = [];   
    if (callback.length) {       
        callback           
            .toString()           
            .replace(commentRegExp, '')
            .replace(cjsRequireRegExp, function (match, dep) {               
                deps.push(dep);
            });
 
        deps = (callback.length === 1 ? ['require'] : ['require', 'exports', 'module']).concat(deps);
 
    }
}

因爲實際項目中的FunctionBody狀況比較複雜,cjsRequireRegExp,這個匹配規則不是很強大,若是在實際項目中發現require有問題的地方, 能夠將FunctionBody手動匹配一下這個正則表達式, 看是否有問題。

exports有什麼好處?

一、相對使用return輸出對象, 因爲js語言特性決定,代碼依次執行, 當模板存在循環依賴關係時,這種export導出就會特別有用。

二、相對於命名空間導出API,它的好處在於它不會影響全局空間, 並且導出的API所屬的對象名稱不會和模塊代碼強耦合。 這也是YUI的模塊API導出方式採用命名空間的一點侷限。

數據或者獨立API模塊

對於一些僅僅提供數據或者獨立方法的模塊,factory格式變爲obj就能夠了, 如:

define({
    camelCase: function(x) {
      return string.camelCase('abc ABC');
    }
});

AMD Plugin Dependency

一個插件依賴應該被描述爲以下格式:

[Plugin Module ID]![resource ID]

目前流行的RequireJS、curl、Dojo等支持AMD的加載器都支持插件, 如加載各類格式的數據,在domReady 完成後在執行操做等。因爲「!」被插件語法佔用,因此在通常資源請求中,請不要使用帶有「!」的URL。 完整的插件清單能夠參考http://requirejs.org/docs/download.html#plugins

下面是兩個RequireJS使用插入的例子:

define([
    'backbone',
    'text!templates.html'
], function( Backbone, template ){
   // ...
});
 
require(['domReady!'], function (doc) {
    //This function is called once the DOM is ready,
    //notice the value for 'domReady!' is the current
    //document.
});

若是讓本身的模塊支持AMD規範

jquery是如何作的?

if ( typeof define === "function" && define.amd && define.amd.jQuery ) {
    define("jquery", [], function () { return jQuery; } );
}

須要在加載中設置:

define.amd = {
    jQuery: true
}; 

小結

AMD僅僅提供了模塊定義的規則,在實際項目使用中還須要考慮一些模塊合併、打包方案等。

目前,實現AMD規範的庫有RequireJS 、curl 、Dojo 、bdLoad 、JSLocalnet 、Nodules等,也有不少庫支持AMD規範,即將本身做爲一個模塊存在,如MooTools 、jQuery 、qwery 、bonzo、firebug等。 在前端模塊化發展如此快的今天,將來應該會有不少庫或者模塊會支持做爲知足AMD、CMD or CommonJS Module規範的模塊存在。

隨着模塊化的發展,高質量的模塊會愈來愈多,爲了讓你們有統一的規則來使用模塊, 模塊規範化就顯得格外重要。 而無論是哪種模塊規範,將來在瀏覽器端前端是否也能夠像Nodejs同樣靈活的去使用知足相同規範,甚至各類不一樣規範的優秀模塊, 這樣就不用將代碼侷限同一種框架中, 或許只是本身瞎想。

 

參考:

http://wiki.commonjs.org/wiki/Modules/1.1.1#Module_Identifiers

https://github.com/amdjs/amdjs-api

https://github.com/requirejs/example-multipage

http://requirejs.org/docs/whyamd.html

相關文章
相關標籤/搜索