requireJs 原理探究以及demo實(shí)現(xiàn)
寫在前面:
大家在開發(fā)中丹莲,天天在使用requireJs,對(duì)于require的核心原理述寡,以及如何實(shí)現(xiàn)一個(gè)簡單的require肯定有所了解找岖,我們今天就聊聊require 。
在require中骑疆,根據(jù)AMD(Asynchronous Module Definition)的思想田篇,即異步模塊加載機(jī)制替废,其思想就是將代碼分為一個(gè)一個(gè)模塊分塊加載,來提高代碼的重用泊柬。
簡單流程概括
- 我們?cè)谑褂胷equireJs時(shí)椎镣,都是在頁面上只引入一個(gè)require.js,把data-main指向我們的main.js
- 運(yùn)行main.js時(shí)兽赁,執(zhí)行里面的require和define方法状答,requireJs會(huì)把這些依賴和回調(diào)方法都用一個(gè)數(shù)據(jù)結(jié)構(gòu)存起來
- 當(dāng)頁面加載時(shí),requireJs 會(huì)根據(jù)依賴預(yù)先先把需要的js通過document.createElement的方法引入dom中刀崖,這樣惊科,被引入dom的script便會(huì)執(zhí)行
- 依賴的js也是根據(jù)requireJs的規(guī)范來寫的,所以他們也會(huì)有define或者require方法亮钦,同樣類似第二步這樣循環(huán)向上查找依賴馆截,同樣會(huì)存起來
- 當(dāng)js需要用到依賴返回的結(jié)果,requireJs會(huì)把保存的方法拿出來并且運(yùn)行
測試代碼
下面是我自己寫的requirJs代碼的測試
index.html
<script src="./myrequire.js" type="text/javascript"></script>
<script type="text/javascript">
require(['util', 'math', 'num'], function (util, math, num) {
num = math.getRadom() + '_' + num;
num = util.formatNum(num);
console.log(num);
});
</script>
util.js
define([], function () {
return {
formatNum: function (n) {
if (n < 10) return '0' + n;
return n;
}
};
});
math.js
define(['num'], function (num) {
return {
getRadom: function () {
return parseInt(Math.random() * num);
}
};
});
num.js
define([], function () {
return 10;
});
這些使用都很簡單,關(guān)鍵在研究myRequireJs的實(shí)現(xiàn)
開始研究
(function(){
//將所有的依賴放在這里
var moduleCache = {};
var require = function(deps,callback) {
var params = []; // 這里放define后面的方法
var depCount = 0;
var i, len, isEmpty = false, modName;
modName = document.currentScript && document.currentScript.id || 'REQUIRE_MAIN';
if(deps.length) {
for(i = 0, len = deps.length; i<len; i++) {
(function(i){
depCount++;
loadMod(deps[i],function(param) {
params[i] = param;
depCount--;
if(depCount == 0) {
saveModule(modName,params,callback);
}
});
})(i)
}
}else {
isEmpty = true;
}
if(isEmpty) {
setTimeout(function() {
saveModule(modName,null,callback);
}, 0);
}
}
var _getPathUrl = function(modName) {
var url = modName;
if(url.indexOf('.js') == -1) url = url + '.js';
return url;
};
var loadMod = function(modName,callback) {
var url = _getPathUrl(modName), fs, mod;
if(moduleCache[modName]) {
mod = moduleCache[modName];
if(mod.status == 'loaded') {
setTimeout(callback(this.params), 0);
} else {
mod.onload.push(callback);
}
}else {
mod = moduleCache[modName] = {
modName: modName,
status: 'loading',
export: null,
onload: [callback]
};
_script = document.createElement('script');
_script.id = modName;
_script.type = 'text/javascript';
_script.charset = 'utf-8';
_script.async = true;
_script.src = url;
fs = document.getElementsByTagName('script')[0];
fs.parentNode.insertBefore(_script, fs);
}
};
var saveModule = function(modName, params, callback) {
var mod, fn;
if(moduleCache.hasOwnProperty(modName)) {
mod = moduleCache[modName];
mod.status = 'loaded';
mod.export = callback ? callback(params) : null;
while(fn = mod.onload.shift()) {
fn(mod.export);
}
} else {
callback && callback.apply(window,params);
}
};
window.require = require;
window.define = require;
})();
代碼流程分析
注: 這里的require 和 define 都用的同一個(gè)通用方法蜂莉,都是通過里面 依賴參數(shù)判斷蜡娶,執(zhí)行同樣的類似方法來實(shí)現(xiàn)這個(gè)效果