requireJS三個測試文件
main.js
require.config({
path: {
"a": "a",
"b": "b"
}
})
require(['a'], function(a) {
console.log('main');
})
a.js
define(['b'], function(b) {
console.log('a');
})
執行結果
b
a.js:2 a
main.js:8 main
可以看到執行順序 b,a.js main.js,即加載完b.js->a.js->main.js
源碼閱讀
構造上下文
打開調試窗口:
這段代碼初始化了一個上下文對象context,調用的是req方法
req = requirejs = function(deps, callback, errback, optional) {
//找到上下文信息,用default:defContextName
var context, config,
contextName = defContextName;
// Determine if have config object in the call.
if (!isArray(deps) && typeof deps !== 'string') {
// deps is a config object
config = deps;
if (isArray(callback)) {
// Adjust args if there are dependencies
deps = callback;
callback = errback;
errback = optional;
} else {
deps = [];
}
}
1.判斷是否是數組
dep傳入的參數是一個數組[‘a’],因爲我們是require([‘a’])
require還可以加載很多模塊,都是通過數組的參數傳入。例如
require(['moduleA', 'moduleB', 'moduleC'], function (moduleA, moduleB, moduleC){
// some code here
});
定義瞭如果deps爲非數組的處理方式
//requireJS判斷數組的方式
var op = Object.prototype,
ostring = op.toString;
function isArray(it) {
return ostring.call(it) === '[object Array]';
}
當然,我們這裏是array,這段函數就跳過去了,如果非數組就拋出異常了;
下一步
2.判斷是否是數組
判斷是否有config,沒有配置參數,也跳過了
if (config && config.context) {
contextName = config.context;
}
config && config.context=undefined,因爲我們沒有指定參數
3.構造上下文
3.1檢測上下文
context=getOwn(contexts,contextName)
81-87
var hasOwn = op.hasOwnProperty, //21
//判斷obj是否有prop屬性
function hasProp(obj, prop) {
return hasOwn.call(obj, prop);
}
function getOwn(obj, prop) {
return hasProp(obj, prop) && obj[prop];
}
這裏的obj是Object,prop是”_“
hasProp(obj, prop)返回的是true
首先檢測obj是否含有prop的屬性,如果有的話,就返回obj[prop],沒有就返回false ,返回的是一個obj._ 也就是Context對象
Module: function (map) {
completeLoad: function (moduleName) {
config: Object
configure: function (cfg) {
contextName: "_"
defQueue: Array[0]
defined: Object
enable: function (depMap) {
execCb: function (name, callback, args, exports) {
load: function (id, url) {
makeModuleMap: function makeModuleMap(name, parentModuleMap, isNormalized, applyMap) {
makeRequire: function (relMap, options) {
makeShimExports: function (value) {
nameToUrl: function (moduleName, ext, skipExt) {
nextTick: function (fn) {
onError: function onError(err, errback) {
onScriptError: function (evt) {
onScriptLoad: function (evt) {
registry: Object
require: function localRequire(deps, callback, errback) {
urlFetched: Object
__proto__: Object
這裏context對象已經存在了,其實我都不知道什麼時候存在的,難道是前幾次加載的時候寫進去的?(相當於緩存)
if (!context) {
context = contexts[contextName] = req.s.newContext(contextName);
}
3.2如果沒有上下文,則構造
前面看到context的結構,那麼context是如何構造的呢?
這裏有一段代碼,因爲每次構造新的context的時候,都會保存進contexts,也就是說已經構建過的依賴將存在contexts中;
//Used to filter out dependencies that are already paths.
req.jsExtRegExp = /^\/|:|\?|\.js$/;
req.isBrowser = isBrowser;
s = req.s = {
contexts: contexts,
newContext: newContext
};
源碼198-1751都在構造上下文,這裏就先跳過。
我們只要知道context的內容就好了。
構造完畢後,第一步進入了context.makeRequire函數
1449-1668行 :localRequire()函數
//Grab defines waiting in the global queue.
intakeDefines();
//Mark all the dependencies as needing to be loaded.
context.nextTick(function() {
//Some defines could have been added since the
//require call, collect them.
intakeDefines();
requireMod = getModule(makeModuleMap(null, relMap));
//Store if map config should be applied to this require
//call for dependencies.
requireMod.skipMap = options.skipMap;
requireMod.init(deps, callback, errback, {
enabled: true
});
checkLoaded();
//將defines放在全局序列中 reqiure中的方法,不是context中的方法了
intakeDefines();
function intakeDefines() {
var args;
//Any defined modules in the global queue, intake them now.
//如果全局隊列有defined modules,現在就進入它們
takeGlobalQueue();
//Make sure any remaining defQueue items get properly processed.
while (defQueue.length) {
args = defQueue.shift();
if (args[0] === null) {
return onError(makeError('mismatch', 'Mismatched anonymous define() module: ' +
args[args.length - 1]));
} else {
//args are id, deps, factory. Should be normalized by the
//define() function.
callGetModule(args);
}
}
context.defQueueMap = {};
}
takeGlobalQueue()是一個內部方法,將全局序列轉化爲context化的序列,具體如何實現的就不細說了,代碼在558-570行。
只是這列有一個疑問,什麼是全局序列,爲什麼會存在全局序列?