1. cmd 和 amd
在瀏覽器中,受網絡和瀏覽器渲染的制約,不能采用同步加載,只能采用異步加載。於是 AMD 規范應運而生
2. AMD
AMD(Asynchronous Module Definition),意思就是"異步模塊定義"。它采用異步方式加載模塊,制定了定義模塊的規則,這樣模塊和模塊的依賴可以被異步加載,不影響它后面語句的運行。所有依賴這個模塊的語句,都定義在一個回調函數中,等到加載完成之后,這個回調函數才會運行。這和瀏覽器的異步加載模塊的環境剛好適應(瀏覽器同步加載模塊會導致性能、可用性、調試和跨域訪問等問題)
2.1 define 函數定義模塊
本規范只定義了一個函數 "define",它是全局變量 define(id?, dependencies?, factory),參數分別是模塊名,依賴,工廠方法
2.2 require(module,callback)加載模塊
- 引入 require.js
<script type=”text/javascript” defer async=”true” src=”./require.js”></script>
<script type=”text/javascript” defer async=”true” src=”js/init.js”></script>
- init.js
//require.config 主要是用來對要加載文件的目錄進行自定義
require.config({
baseUrl: 'js',
paths: {
"jquery": "../lib/jquery",
"undersocre": "../lib/underscore",
}
})
require(['jquery', 'underscore'], function ($, _) {
$(window).resize(function () {
var color = ["rgba(", Math.floor(Math.random() * 255), ",", Math.floor(Math.random() * 255), ",", Math.floor(Math.random() * 255), ")"];
$(".background").css({
position: "fixed",
top: "0px",
bottom: "0px",
left: "0px",
right: "0px",
background: color.join("")
});
})
});
第一個參數是一個數組,值是依賴的模塊。回調事件會在所有依賴模塊加載完畢后才會執行
2.3 預加載,在定義模塊的時候就提前加載好所有模塊
3. CMD
該規范解決的瀏覽器環境下如何編寫代碼實現模塊化,該規范定義可模塊的一些遵循的特征,來支持能共用的模塊
- 模塊單一文件
- 不應引入模塊作用域范圍內的新的自由變量
- 懶加載
3.1 模塊定義
define(factory)定義模塊
- define 函數接受一個參數作為模塊工廠
- factory 可以是一個函數或者其他有效值
- 如果 factory 是一個函數,回調函數中會指定三個參數 require,exports,module
- 如果個 factory 不是一個函數(對象,字符串),這是模塊的接口就是當前對象,字符串
define(function(require, exports, module) {
// do something
});
3.2 require
- require 函數接收一個模塊標識符(模塊標識符也叫模塊 id)。
- require 函數返回外部模塊的導出 API(”導出 API“是用來導出內容給外部模塊使用的)。
- 如果無法返回請求的模塊, require 函數將返回 null。
3.3 require.async
- require.async 接收一個模塊 Id 列表和一個可選的回調函數。
- 回調函數接收模塊導出作為函數參數,按照與第一個參數中的順序相同的順序列出。
- 如果不能返回請求的模塊,則回調應該相應地收到 null。
3.4 exports 對象
每個模塊中都有個名叫"exports"的自由變量,這是一個模塊可以在模塊執行時添加模塊 API 的對象。
3.5 module 對象
- module.uri:完整解析的模塊 URI(模塊 URI 的全路徑)。
- module.dependencies:模塊請求的標識符(模塊 id)列表。
- module.exports:模塊的導出 API(”導出 API“是”用來導出什么東西的 API“)。 它與 export 對象相同。
3.6 模塊標識符(模塊 id)
- 模塊的標識符(模塊 id)必須是字面量字符串。
- 模塊標識符(模塊 id)不能有類似 .js 的文件名擴展。
- 模塊標識符(模塊 id)應該是加前/后綴的字符串,比如:foo-bar。
- 模塊標識符(模塊 id)可以是相對路徑,例如: ./foo 和 ../bar.。
懶加載,在 require 時候才會加載模塊
3.7 一個簡單的示例(seajs)
這是 seajs 對象上綁定的屬性和方法
color.js
define("color", function(require, exports, module) {
var \$ = require("jquery");
var createColor = function() {
return ["rgba(", Math.floor(Math.random() * 255), ",", Math.floor(Math.random() * 255), ",", Math.floor(Math.random() * 255), ")"];
};
module.exports = {
changeBg: function() {
\$("#bg").css({
position: "fixed",
top: "0px",
bottom: "0px",
left: "0px",
right: "0px",
background: createColor().join("")
});
}
};
});
使用非函數的工廠包裝模塊 text.js
define({
text: "我是初始化程序",
text2: "我要開始執行了"
});
init.js
define("init", function(require, exports, module) {
var color = require("../src/color");
var initText = require("../src/text");
var \$ = require("jquery");
module.exports = {
start: function() {
console.log(initText.text + "," + initText.text2);
$(function() {
$("#change").click(function() {
color.changeBg();
});
});
}
};
});
sea.js.html
...
<body id="bg">
<button id="change">點我我變色</button>
</body>
<script src="./lib/sea.js"></script>
<script>
seajs.config({
alias: {
underscore: "underscore.js",
init: "./src/init.js",
color: "./src/color.js"
}
});
seajs.use(["underscore", "init"], function(u, init) {
init.start();
});
</script>
...
目錄結構
3.8 seajs 引入其他插件或庫
一般控制台報錯 xxx is not a function
一些庫不支持模塊引入或者只支持 amd 規范的引入方式,不支持 cmd。所有需要對庫進行一些改造
//Underscore.js 1.9.1
if (typeof define === "function" && define.amd && define.amd.jQuery) {
define("underscore", [], function() {
return \_;
});
}
//更改如下
if (typeof define === "function" && (define.amd || define.cmd)) {
define("underscore", [], function() {
return _;
});
}
//或者整個 define 的判斷不要了
if (typeof define === "function") {
define("underscore", [], function() {
return _;
});
}
UMD
是一種思想,就是一種兼容 commonjs,AMD,CMD 的兼容寫法,define.amd / define.cmd / module 等判斷當前支持什么方式,都不行就掛載到 window 全局對象上面去
(function (root, factory) {
if (typeof define === 'function' && (define.amd || define.cmd)) {
//AMD,CMD
define(['b'], function(b){
return (root.returnExportsGlobal = factory(b))
});
} else if (typeof module === 'object' && module.exports) {
//Node, CommonJS之類的
module.exports = factory(require('b'));
} else {
//公開暴露給全局對象
root.returnExports = factory(root.b);
}
}(this, function (b) {
return {};
}));