AMD,js加載過多頁面中止響應,前端
使用js異步加載方式jquery
1.爲解決js加載阻塞json
2.解決js文件依賴的問題api
AMD規範:是 RequireJS 在推廣過程當中對模塊定義的規範化產出的,而CMD規範:是SeaJS 在推廣過程當中對模塊定義的規範化產出的。dom
什麼是CMD規範?異步
在CMD中 一個模塊就是一個文件,以下代碼所示:async
//基本格式如:define(id, deps, factory)
//通常格式如:define(factory)
//模塊代碼 define('hello',['jQuery'],function(require, exports, module) { });
define是一個全局函數,主要是用來定於模塊的。
'hello'就是模塊名稱,
['jquery']是依賴項,也能夠依賴於多項能夠以下寫法['jquery','',''],分別用逗號隔開,
id(模塊名稱)和deps(被依賴項) 是能夠省略的。
省略時,那麼模塊名稱就是文件名稱。好比我有個文件叫a.js,那麼我定義模塊時候以下代碼所示:
//模塊代碼define(function(require, exports, module) { });
那麼若是我想在b.js代碼裏面要依賴於a.js的話,那麼我能夠直接這樣寫:
define(function(require,exports,module){ var a = require('a')});
可是注意:帶有id 和 deps 是不屬於CMD規範的。因此在seaJS裏面 通常的寫法是不帶模塊名稱和依賴項的。就是如上的代碼格式。
下面看看 factory 在seajs裏面 factory既能夠是函數,對象或者字符串。factory爲對象 字符串時候,表示該模塊的接口就是該對象或者字符串,以下能夠定義一個json對象。
define({"aa":'bb'});和jsonp格式相似,不過這樣的數據對象是高度可用的,並且由於是靜態對象,他也是CDN友好的,能夠提升性能,
好比說咱們 有個省市區這麼一個jSON格式要返回咱們前端,若是以傳統JSONP的形式提供給客戶端,它必須提供一個callback函數名,根據這個函數名動態生成返回數據,這使得標準JSONP數據必定不是CDN友好的。那麼咱們能夠利用這種格式
define({ provinces: [ { name: '上海', areas: ['浦東新區', '徐彙區']}, { name: '江蘇', cities: ['南京', '南通']} //..... ] });
假設這個文件名爲china.js,那麼若是某個模塊須要這個數據,只須要:
define(function(require,exports,module){
var china = require('./china'); //在這裏使用中國省市數據 });
當factory爲函數時,表示該模塊的構造方法,執行該構造方法,能夠獲得模塊向外提供的接口。默認會傳入三個參數require,exports,module.那麼咱們先來看看require參數吧!
require:
那麼如今我想在b.js裏面調用a.js裏面的a方法。咱們能夠以下作:函數
define(function(require,exports){性能
var fun = require('./a');jsonp
console.log(fun.a()); // 就能夠調用到及執行a函數了。
exports.a = function(){
// 不少代碼
};
})
require.async(id,callback) : require.async: 方法用來在模塊內部異步加載模塊,並在加載完成後執行指定回調。callback參數可選。好比以下代碼:
define(function(require, exports, module) { // 異步加載一個模塊,在加載完成時,執行回調 require.async('./b', function(b) { b.doSomething(); }); // 異步加載多個模塊,在加載完成時,執行回調 require.async(['./c', './d'], function(c, d) { c.doSomething(); d.doSomething(); }); });
注意: require是同步往下執行的,而require.async 則是異步回調執行。
require.resolve(id)
使用模塊系統內部的路徑解析機制來解析並返回模塊路徑。該函數不會加載模塊,只返回解析後的絕對路徑。
define(function(require, exports) { console.log(require.resolve('./b')); // ==> http://example.com/path/to/b.js });
exports
exports:是一個對象,用來向外提供模塊接口。
好比仍是上面的代碼:以下a.js裏面
define(function(require, exports) { exports.a = function(){ // 不少代碼 }; });
或者以下書寫:
define(function(require, exports) { return { i: 'a', a: function(){ // 執行相應的代碼 } } });
那麼若是我在b.js裏面想要調用a.js裏面的a方法,因爲a.js使用exports對外提供了接口a方法,那麼在b.js裏面 咱們只須要先這樣 var fun = require('./a');而後執行fun.a();就能夠執行a方法了。
module
module 是一個對象,上面存儲了與當前模塊相關聯的一些屬性和方法。其中exports是module.exports的一個引用。
module.exports的一個引用。
moudle.id
moudle.id
模塊的惟一標識。以下代碼:
define('id', [], function(require, exports, module) { // 模塊代碼 });
module.uri
根據模塊系統的路徑解析規則獲得的模塊絕對路徑。
define(function(require, exports, module) { console.log(module.uri); // ==> http://example.com/path/to/this/file.js });
等等屬性 具體能夠看seajs官網。原理是同樣的 由於seajs也採用的是CMD規範。
什麼是AMD規範?
以下官網代碼:
define("alpha", ["require", "exports", "beta"], function (require, exports, beta) { exports.verb = function() { return beta.verb(); //或者: return require("beta").verb(); } });
這裏的require函數讓你可以隨時去依賴一個模塊,即取得模塊的引用,從而即便模塊沒有做爲參數定義,也可以被使用;exports是定義的 alpha 模塊的實體,在其上定義的任何屬性和方法也就是alpha模塊的屬性和方法。
經過exports.verb = ...就是爲alpha模塊定義了一個verb方法。例子中是簡單調用了模塊beta的verb方法。
其中上面的模塊名稱和依賴項 也能夠省略,那麼若是省略的話,那麼咱們能夠稱他們爲匿名函數,那麼一樣 模塊名稱就是文件名稱 和上面的CMD規範相似。
上面的['',''] 參數表明了一組對所定義的模塊來講必須的依賴項。第三個參數('definition function')是一個用來爲你的模塊執行初始化的函數。一個最簡單的模塊能夠以以下方式定義:
// 模塊定義函數 // 依賴項(foo 和 bar)被映射爲函數的參數 define('myMoudle',['foo','bar'],function(foo,bar){ // 返回一個定義了模塊導出接口的值 // (也就是咱們想要導出後進行調用的功能) // 在這裏建立模塊 var myModule = { doStuff:function(){ console.log('Yay! Stuff'); } } return myModule; });
還能夠這樣書寫:
// 另外一個例子能夠是... define('myModule',['math', 'graph'], function ( math, graph ) { // 請注意這是一個和 AMD 有些許不一樣的模式,但用幾種不一樣的方式 // 來定義模塊也是能夠的,由於語法在某些方面仍是比較靈活的 return { plot: function(x, y){ return graph.drawPie(math.randomGrid(x,y)); } } }; });
另外一方面,require 則主要用來在頂層 JavaScript 文件中或需要動態讀取依賴時加載代碼。用法的一個實例以下:
// 假設 'foo' 和 'bar' 是兩個外部模塊 // 在本例中,這兩個模塊被加載後的 'exports' 被當作兩個參數傳遞到了回調函數中 // 因此能夠像這樣來訪問他們 require(['foo', 'bar'], function ( foo, bar ) { // 這裏寫其他的代碼 foo.doSomething(); });
define(function ( require ) { var isReady = false, foobar; // 請注意在模塊定義內部內聯的 require 語句 require(['foo', 'bar'], function (foo, bar) { isReady = true; foobar = foo() + bar(); }); // 咱們仍能夠返回一個模塊 return { isReady: isReady, foobar: foobar }; });
CMD規範與AMD規範的區別以下:
1. CMD依賴就近:好比以下代碼
define(function(require,exports,module){ var a = require('./a'); a.doSomthing(); });
代碼在運行時,首先是不知道依賴的,須要遍歷全部的require關鍵字,找出後面的依賴。具體作法是將function toString後,用正則匹配出require關鍵字後面的依賴。
而AMD依賴前置:以下代碼:
define(['./a','./b'],function(a,b){ //...... a.doSomthing(); //...... b.doSomthing(); })
代碼在一旦運行到此處,能當即知曉依賴。而無需遍歷整個函數體找到它的依賴,所以性能有所提高,缺點就是開發者必須顯式得指明依賴——這會使得開發工做量變大,好比:當依賴項有n個時候 那麼寫起來比較煩 且容易出錯。不過 RequireJS 從 2.0 開始,也改爲能夠延遲執行(根據寫法不一樣,處理方式不一樣)。
2. 執行順序上:
CMD是延遲執行的,而AMD是提早執行的。
3. api設計角度:
AMD 的 API 默認是一個當多個用,CMD 的 API 嚴格區分,推崇職責單一。好比 AMD 裏,require 分全局 require 和局部 require,都叫 require。CMD 裏,沒有全局 require,而是根據模塊系統的完備性,提供 seajs.use 來實現模塊系統的加載啓動。CMD 裏,每一個 API 都簡單純粹。