说明:
内容主要包括三部分:
1.按源码的结构顺序 对 所有的变量及方法的说明
2.requirejs运行流程
3、流程相关图片
一、源码的结构
为了方便比对源码,按源码的结构顺序展示。
var requirejs, require, define;
(function (global, setTimeout) {
var req, s, head, baseElement, dataMain, src,
interactiveScript, currentlyAddingScript, mainScript, subPath,
version = '2.3.5',
commentRegExp = /\/\*[\s\S]*?\*\/|([^:"'=]|^)\/\/.*$/mg, //去除注释
cjsRequireRegExp = /[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g,//提取require函数的arguments
jsSuffixRegExp = /\.js$/,
currDirRegExp = /^\.\//,
op = Object.prototype,
ostring = op.toString,
hasOwn = op.hasOwnProperty,
isBrowser = !!(typeof window !== 'undefined' && typeof navigator !== 'undefined' && window.document),
isWebWorker = !isBrowser && typeof importScripts !== 'undefined',
readyRegExp = isBrowser && navigator.platform === 'PLAYSTATION 3' ?
/^complete$/ : /^(complete|loaded)$/,
defContextName = '_',
isOpera = typeof opera !== 'undefined' && opera.toString() === '[object Opera]',
contexts = {},
cfg = {},
globalDefQueue = [],
useInteractive = false;
//返回singlePrefix或空
function commentReplace(match, singlePrefix) {}
//判断函数
function isFunction(it) {}
//判断数组
function isArray(it) {}
//执行函数func(ary[i], i, ary);返回真值,跳出循环
function each(ary, func) {}
//与each序列反
function eachReverse(ary, func) {}
//判断obj是否有prop
function hasProp(obj, prop) {}
//返回obj上的prop
function getOwn(obj, prop) {}
//循环调用func(obj[prop], prop);返回真值,跳出循环
function eachProp(obj, func) {}
//混合source属性值(target没有同名的)到target
//force为真,target同名覆盖,deepStringMixin为真,深混合
function mixin(target, source, force, deepStringMixin) {}
//返回逆名函数,执行为obj调用fn函数
function bind(obj, fn) {}
//返回script元素的集合
function scripts() {}
//throw err;
function defaultOnError(err) {}
//例getGlobal("aa.bb");为global.aa.bb
function getGlobal(value) {}
//生成一个错误
function makeError(id, msg, err, requireModules) {}
if (typeof define !== 'undefined') {
return;
}
if (typeof requirejs !== 'undefined') {
if (isFunction(requirejs)) {
return;
}
cfg = requirejs;
requirejs = undefined;
}
if (typeof require !== 'undefined' && !isFunction(require)) {
cfg = require;
require = undefined;
}
function newContext(contextName) {
var inCheckLoaded, Module, context, handlers,
checkLoadedTimeoutId,
config = {
waitSeconds: 7,
baseUrl: './',
paths: {},
bundles: {},
pkgs: {},
shim: {},
config: {}
},
registry = {},
enabledRegistry = {},
undefEvents = {},
defQueue = [],
defined = {},
urlFetched = {},
bundlesMap = {},
requireCounter = 1,
unnormalizedCounter = 1;
//ary中.删除此项;..删此项和前一项除(i === 0 || (i === 1 && ary[2] === '..') || ary[i - 1]==='..')
function trimDots(ary) {}
//路径处理.config.pkgs有name值优先,无值按相对路径转化,apply是否启用地图配置
function normalize(name, baseName, applyMap) {}
//删除data-requiremoduley为name和data-requirecontext === context.contextName的script
function removeScript(name) {}
//先移除再加载模块;
function hasPathFallback(id) {}
//第一个"!"分离的前后数据 return [prefix, name];
function splitPrefix(name) {}
//返回模块的属性对象
// return {
// prefix: prefix,
// name: normalizedName,
// parentMap: parentModuleMap,
// unnormalized: !!suffix,
// url: url,
// originalName: originalName,
// isDefine: isDefine,
// id: (prefix ?
// prefix + '!' + normalizedName :
// normalizedName) + suffix
// };
function makeModuleMap(name, parentModuleMap, isNormalized, applyMap) {}
//registry[id]有值取值,没值生成新的context.Module对象,并赋给registry[id]
function getModule(depMap) {}
//模块加载完且name为defined 或 加载出错且name为error ? 执行fn : 模块绑定事件
function on(depMap, name, fn) {}
//errback ? 执行errback(err) : mod.emit('error', err)执行删除操作
function onError(err, errback) {}
//将globalDefQueue推入defQueue
function takeGlobalQueue() {}
//commonjs风格
handlers = {
//mod.require ? 返回mod.require : localRequire
'require': function (mod) {},
'exports': function (mod) {},
'module': function (mod) {}
};
//清除registry[id]、enabledRegistry[id]
function cleanRegistry(id) {}
//递归mod.depMaps,执行mod.check();
function breakCycle(mod, traced, processed) {}
//检查加载状态,不同状态执行不同操作
function checkLoaded() {}
Module = function (map) {
this.events = getOwn(undefEvents, map.id) || {};
this.map = map;
this.shim = getOwn(config.shim, map.id);
this.depExports = [];
this.depMaps = [];
this.depMatched = [];
this.pluginMaps = {};
this.depCount = 0;
};
Module.prototype = {
//初始化,根据options.enabled ? this.enable() : this.check()
init: function (depMaps, factory, errback, options) {},
//通过this.depCount判断依赖是否加载完成
defineDep: function (i, depExports) {},
// map.prefix ? this.callPlugin() : this.load();
fetch: function () {},
//通过context.load调req.load加载js文件
load: function () {},
//define模块调用
check: function () {},
//加载依赖
callPlugin: function () {},
//data-main上的模块调用,define模块调用
enable: function () {},
//将cb推入this.events[name]
on: function (name, cb) {},
//name === 'error'删this.events[name];否则循环this.events[name]执行cb(evt);
emit: function (name, evt) {}
};
//module.init内执行check()非enable();
function callGetModule(args) {}
//移除监听事件
function removeListener(node, func, name, ieName) {}
//移除监听事件,返回节点
function getScriptData(evt) {}
// 获取并加载defQueue中的模块
function intakeDefines() {}
context = {
config: config,
contextName: contextName,
registry: registry,
defined: defined,
urlFetched: urlFetched,
defQueue: defQueue,
defQueueMap: {},
Module: Module,
makeModuleMap: makeModuleMap,
nextTick: req.nextTick,
onError: onError,
//配置参数 调用context.require(cfg.deps || [], cfg.callback);
configure: function (cfg) {},
//返回闭包接口供调用
makeShimExports: function (value) {},
//返回闭包接口供调用
makeRequire: function (relMap, options) {
//makeRequire的实际执行函数,生成宏任务;
function localRequire(deps, callback, errback) {
return localRequire;
}
mixin(localRequire, {
isBrowser: isBrowser,
toUrl: function (moduleNamePlusExt) {},
defined: function (id) {},
specified: function (id) {}
});
if (!relMap) {
localRequire.undef = function (id) {};
}
return localRequire;
},
//调用 module的enable()
enable: function (depMap) {},
//完成加载后
completeLoad: function (moduleName) {},
//根据moduleName获取url
nameToUrl: function (moduleName, ext, skipExt) {},
//调用req.load()
load: function (id, url) {},
//return callback.apply(exports, args);
execCb: function (name, callback, args, exports) {},
//加载完成后
onScriptLoad: function (evt) {},
//加载错误
onScriptError: function (evt) {}
};
context.require = context.makeRequire();
return context;
}
//入口函数
req = requirejs = function (deps, callback, errback, optional) {};
//return req(config);
req.config = function (config) {};
//宏任务
req.nextTick = typeof setTimeout !== 'undefined' ? function (fn) {
setTimeout(fn, 4);
} : function (fn) { fn(); };
//req赋值给require
if (!require) {
require = req;
}
req.version = version;
req.jsExtRegExp = /^\/|:|\?|\.js$/;
req.isBrowser = isBrowser;
s = req.s = {
contexts: contexts,
newContext: newContext
};
//初始调用
req({});
each([
'toUrl',
'undef',
'defined',
'specified'
], function (prop) {
req[prop] = function () {
var ctx = contexts[defContextName];
return ctx.require[prop].apply(ctx, arguments);
};
});
if (isBrowser) {
head = s.head = document.getElementsByTagName('head')[0];
baseElement = document.getElementsByTagName('base')[0];
if (baseElement) {
head = s.head = baseElement.parentNode;
}
}
req.onError = defaultOnError;
//创建节点
req.createNode = function (config, moduleName, url) {};
//节点绑定事件,添加到头部,并返回节点
req.load = function (context, moduleName, url) {};
//返回状态为interactive的节点
function getInteractiveScript() {}
//data-main上的值解析赋给cfg
if (isBrowser && !cfg.skipDataMain) {
eachReverse(scripts(), function (script) {
if (!head) {
head = script.parentNode;
}
dataMain = script.getAttribute('data-main');
if (dataMain) {
mainScript = dataMain;
if (!cfg.baseUrl && mainScript.indexOf('!') === -1) {
src = mainScript.split('/');
mainScript = src.pop();
subPath = src.length ? src.join('/') + '/' : './';
cfg.baseUrl = subPath;
}
mainScript = mainScript.replace(jsSuffixRegExp, '');
if (req.jsExtRegExp.test(mainScript)) {
mainScript = dataMain;
}
cfg.deps = cfg.deps ? cfg.deps.concat(mainScript) : [mainScript];
return true;
}
});
}
//定义模块的函数
define = function (name, deps, callback) {};
define.amd = {
jQuery: true
};
req.exec = function (text) {};
//将data-main的值解析代入req函数;
req(cfg);
}(this, (typeof setTimeout === 'undefined' ? undefined : setTimeout)));
二、详细流程
1、初始化变量;
2、执行 req({})
req({})
context = contexts[contextName] = req.s.newContext(contextName);
说明:contextName='_',返回context这个东西,context.require = context.makeRequire();=localRequire;调用makeRequire实际调用makeRequire里的localRequire
context.configure(cfg);
说明:cfg=config={},什么都没干
return context.require(deps, callback, errback);
说明:调用makeRequire里的localRequire;deps=[];
intakeDefines();
takeGlobalQueue();
说明:intakeDefines的子函数,两者什么都没执行
context.nextTick(function () {
intakeDefines();
requireMod = getModule(makeModuleMap(null, relMap));
requireMod.skipMap = options.skipMap;
requireMod.init(deps, callback, errback, {
enabled: true
});
checkLoaded();
});
说明:产生一个 宏任务1 函数;req({})函数完
3、执行 req(cfg)
获取data-main上的值并解析成cfg
req(cfg);
说明:cfg={baseUrl:"data-main解析值1",deps:[data-main解析值2]}
context = getOwn(contexts, contextName);
说明:获取之前产生的context;
context.configure(cfg);
说明:cfg=config={baseUrl:"data-main解析值1",deps:[data-main解析值2]}
config[prop] = value;
说明:属性值给config
context.require(cfg.deps || [], cfg.callback);
说明:调用makeRequire里的localRequire;deps=[data-main解析值2];
intakeDefines();
takeGlobalQueue();
说明:什么都没执行
context.nextTick(function () {
说明:产生一个 宏任务2 函数;
return context.require(deps, callback, errback);
说明:调用makeRequire里的localRequire;deps=[];
intakeDefines();
takeGlobalQueue();
说明:什么都没执行
context.nextTick(function () {
说明:产生一个 宏任务3 函数;req(cfg);函数完
4、第一个宏任务开始
intakeDefines();
takeGlobalQueue();
说明:什么都没执行
requireMod = getModule(makeModuleMap(null, relMap));
makeModuleMap(null, relMap)
说明:返回一个对象obj
nameParts = splitPrefix(name);
说明:name="_@r2"
normalizedName = normalize(name, parentName, applyMap);
url = context.nameToUrl(normalizedName);
parentModule = syms.slice(0, i).join('/');
说明:parentModule="_@r2"
getModule(obj)
new context.Module(depMap)
说明:depMap=上面返回的对象obj;getModule返回context.Module实例requireMod
requireMod.init(deps, callback, errback, {enabled: true});
this.enable();
enabledRegistry[this.map.id] = this;
this.check();
cleanRegistry(id);
this.emit('defined', this.exports);
checkLoaded();
说明:什么都没执行,第一个宏任务完。
5、第二个宏任务开始
intakeDefines();
takeGlobalQueue();
说明:什么都没执行
requireMod = getModule(makeModuleMap(null, relMap));
makeModuleMap(null, relMap)
说明:返回一个对象obj
nameParts = splitPrefix(name);
说明:name="_@r3"
normalizedName = normalize(name, parentName, applyMap);
url = context.nameToUrl(normalizedName);
parentModule = syms.slice(0, i).join('/');
说明:parentModule="_@r3"
getModule(obj)
new context.Module(depMap)
说明:depMap=上面返回的对象obj;getModule返回context.Module实例requireMod
requireMod.init(deps, callback, errback, {enabled: true});
说明: deps 变为 data-main解析值2
this.enable();
enabledRegistry[this.map.id] = this;
depMap = makeModuleMap(depMap,(this.map.isDefine ? this.map : this.map.parentMap), false,!this.skipMap);
nameParts = splitPrefix(name);
normalizedName = normalize(name, parentName, applyMap);
url = context.nameToUrl(normalizedName);
" on(depMap, 'defined', bind(this, function (depExports) {this.defineDep(i, depExports);this.check();}));
"
mod = getModule(depMap);
mod = registry[id] = new context.Module(depMap);
mod.on(name, fn);
getModule(depMap).enable();
this.check();
checkLoaded();
说明: 宏任务2结束
6、宏任务3同宏任务1
7、执行data-main引入的文件的require函数
require(['./example'],function(example){example.test();});
req = requirejs = function (deps, callback, errback, optional) {
return context.require(deps, callback, errback);
intakeDefines();
takeGlobalQueue();
context.nextTick(function () {
说明: 产生一个宏任务4函数;require函数结束
onScriptLoad: function (evt) {
var data = getScriptData(evt);
context.completeLoad(data.id);
shim = getOwn(config.shim, moduleName) || {},
takeGlobalQueue();
callGetModule([moduleName, (shim.deps || []), shim.exportsFn]);
说明: require函数结束后执行
8、宏任务4同宏任务2
说明: deps变为 要加载的依赖