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行。
只是这列有一个疑问,什么是全局序列,为什么会存在全局序列?