一、require使用方法
require遵循AMD规范
也就是通过在加载模块时注册回调函数的方式,当所需模块加载完成后,再去执行回调
这样就保证了不会因所需模块未加载而造成的错误
<script src="./js/require.js" data-main="./js/main.js"></script>
使用时需要加上data-main属性,指向脚本文件的入口文件位置
二、开始分析
1.给定了入口文件位置,第一步肯定要找到入口文件具体额位置
#2007-#2052
于是我发现了下面这段代码:
//Look for a data-main script attribute, which could also adjust the baseUrl.
if (isBrowser && !cfg.skipDataMain) {
//Figure out baseUrl. Get it from the script tag with require.js in it.
eachReverse(scripts(), function (script) {
//Set the 'head' where we can append children by
//using the script's parent.
if (!head) {
head = script.parentNode;
}
//Look for a data-main attribute to set main script for the page
//to load. If it is there, the path to data main becomes the
//baseUrl, if it is not already set.
dataMain = script.getAttribute('data-main');
if (dataMain) {
// ........... 此处省略一万字
return true;
}
});
}
isBrowser 判断了是否是浏览器环境
isBrowser = !!(typeof window !== 'undefined' && typeof navigator !== 'undefined' && window.document)
这种判断方式确实以前没有见到过!
2. 之后进入到eachReverse函数中
/**
* Helper function for iterating over an array backwards. If the func
* returns a true value, it will break out of the loop.
*/
function eachReverse(ary, func) {
if (ary) {
var i;
for (i = ary.length - 1; i > -1; i -= 1) {
if (ary[i] && func(ary[i], i, ary)) {
break;
}
}
}
}
官方给的注释也非常详细,这是一个用于迭代一个数组中的每个成员的函数,且回调函数func执行结果为true时便会立即退出迭代过程
调用此函数第一步传入scripts()函数的返回值
这个函数没什么好说的,返回全部的script标签数组
function scripts() {
return document.getElementsByTagName('script');
}
然后相当于遍历了所有的script标签,直到取到一个带有data-main属性的标签
dataMain = script.getAttribute('data-main');
if (dataMain) {
mainScript = dataMain;
//==========================================================
//如果没有定义配置对象中的baseUrl 并且 此路径不是插件
//require.js中使用!表示插件
//==========================================================
if (!cfg.baseUrl && mainScript.indexOf('!') === -1) {
//Pull off the directory of data-main for use as the
//baseUrl.
src = mainScript.split('/');
mainScript = src.pop();
subPath = src.length ? src.join('/') + '/' : './';
cfg.baseUrl = subPath;
//==========================================================
//这里应该是对不同情况下的入口文件路径做了适配
/*
比如路径是"./js/index.js"
先切分成数组src = [".","js","index.js"]
mainScript = "."
src = [".","js"]
subPath = 2 ? src.join('/') + '/' : './' = src.join('/') + '/'
= "./js/"
之后赋值给baseUrl 也就做到了默认读取其他模块从此路径下进行读取
*/
//==========================================================
}
//==========================================================
去掉文件结尾的.js文件
//==========================================================
mainScript = mainScript.replace(jsSuffixRegExp, '');
if (req.jsExtRegExp.test(mainScript)) {
mainScript = dataMain;
}
cfg.deps = cfg.deps ? cfg.deps.concat(mainScript) : [mainScript];
return true;
}
参考资料
阮一峰老师的博客——js模块化编程
require.js下载(学习的话选择有注释的版本就行了(With Comments))