RequireJS:javascript的模块加载器,非常适合在浏览器中使用(兼容性强)
思考:如何实现define 、module、require(模块名加载、远程资源加载、nodejs端加载)
先熟悉requireJs的使用方法
第一步
//在页面中引入require.js,指定主文件main.js
<script src="js/require.js" data-main="js/main"></script>
第二步
//vue.js 定义vue模块,以及依赖的javascript模块
define('vue',['javascript'],function (){
return orange
});
//javascript.js 定义javascript模块,无依赖
define('javascript',[],function (){
return {
name:'js',
type:'脚本语言',
content: '学无止尽',
}
});
第三步
//在main文件中,使用定义好的vue模块
require(['vue'], function (vm){
console.log(vm)
//===>输出
{
name:'js',
type:'脚本语言',
content: '学无止尽',
}
});
猜测运行过程
- 加载requireJs,其中定义了define、require等方法
- 取得script标签中的data-main属性
- 加载main.js文件
- 文件中的require方法请求vue模块,异步加载vue
- vue模块中异步加载javascript模块
- math加载成功后,执行回调函数,打印出了javascript
函数
require:require(dep?,cb) 简易实现:
//标记已经加载成功的个数
var REQ_TOTAL = 0;
//模块导出
window.exports = {};
//记录各个模块的顺序
var exp_arr = [];
function require(arr, callback) {
//默认为数组类型,且未处理路径问题
var req_list = arr
var req_len = req_list.length;
//模块逐个加载,动态加载script标签
for(var i=0;i<req_len;i++) {
var req_item = req_list[i];
var $script = createScript(req_item, i);
var $node = document.querySelector('head');
(function($script) {
//检测script 的onload事件
$script.onload = function() {
REQ_TOTAL++;
var script_index = $script.getAttribute('index');
exp_arr[script_index] = exports;
window.exports = {};
//所有链接加载成功后,执行callback,并传入导出的exports数组
if(REQ_TOTAL == req_len) {
callback && callback.apply(exports, exp_arr);
}
}
$node.appendChild($script);
})($script);
}
}
//创建一个script标签,用index标记顺序
function createScript(src, index) {
var $script = document.createElement('script');
$script.setAttribute('src', src);
$script.setAttribute('index', index);
return $script;
}
define:define(name?,[]? , callback);
这个name可以省掉,默认是文件名称;也可以自定义,一旦定义了name,define函数内部其实就是把这个name以及依赖模块、回调函数作为一个对象存储在全局的数组当中,也就是 defQueue.push([name,deps,callback]);这个name就是这个组件注册的的ID。并且通过defQueueMap对象以id为key建立对应的映射关系。
//对象字面量,存储对应的module
var moudules={};
function define(name,deps,callback){
for(var i=0;i<deps.length;i++){
//modules存在则直接取
deps[i]=moudules[deps[i]];
}
//name为id调用callback方法并缓存
moudules[name]=callback.apply(callback,deps);
console.log(moudules[name]);
}
//获取module的方法
function get(name){
return moudules[name];
}
return {
define:define,
get:get
};
待优化
1.定义模块映射表,也就是require.config
2.循环依赖的问题:将依赖放入一颗全局依赖树,进行去重操作