模块加载,其实就是把js分成很多个模块,便于开发和维护。因此加载很多js模块的时候,需要动态的加载,以便提高用户体验。
在介绍模块加载库之前,先介绍一个方法。
动态加载js方法:
复制代码 代码如下:
function loadJs(url , callback){
var node = document.createElement("script");
node[window.addEventListener ? "onload":"onreadystatechange"] = function(){
if(window.addEventListener || /loaded|complete/i.test(node.readyState)){
callback();
node.onreadystatechange = null;
}
}
node.onerror = function(){};
node.src = url;
var head = document.getElementsByTagName("head")[0];
head.insertBefore(node,head.firstChild); //插入到head的第一个节点前,防止ie6下head标签没闭合前,使用appendChild报错。
}
由于司徒正美使用了它写的mass框架来介绍模块加载,而业界用的最多的是require.js和sea.js。因此,我觉得他个性有点强。
我来讲下sea.js的模块加载过程吧:
页面chaojidan.jsp,在head标签中,引入sea.js,这时就会得到seajs对象。
同时引入index.js。
index.js的代码如下:
复制代码 代码如下:
seajs.use(['./a','jquery'],function(a,$){
var num = a.a;
$('#J_A').text(num);
})
a.js :
复制代码 代码如下:
define(function(require,exports,module){
var b = require('./b');
var a = function(){
return 1 + parseInt(b.b());
}
exports.a = a;
})
b.js :
复制代码 代码如下:
define(function(require,exports,module){
var c = require('./c');
var b = function(){
return 2 + parseInt(c.c());
}
exports.b = b;
})
c.js :
复制代码 代码如下:
define(function(require,exports,module){
var c = function(){
return 3;
}
exports.c = c;
})
由上可知,a模块依赖b,b依赖c.
当程序进入到index.js,seajs将调用use方法。
复制代码 代码如下:
seajs.use = function(ids, callback) {
globalModule._use(ids, callback)
}
说明: globalModule 为seajs初始化时(引入sea.js时),Module的实例 var globalModule = new Module(util.pageUri, STATUS.COMPILED)
此时 ids -> ['./a','jquery'], callback -> function(a,$){var num = a.a;$('#J_A').text(num);}
接下来将调用 globalModule._use(ids, callback)
复制代码 代码如下:
Module.prototype._use = function(ids, callback) {
var uris = resolve(ids, this.uri); //解析['./a','jquery']
this._load(uris, function() { //把解析出来的a,jquery模块的地址[url1,url2],调用_load方法。
//util.map : 让数据成员全部执行一次一个指定的函数,并返回一个新的数组,该数组为原数组成员执行回调后的结果
var args = util.map(uris, function(uri) {
return uri ? cachedModules[uri]._compile() : null;//如果存在url,就调用_compile方法。
})
if (callback) { callback.apply(null, args) }
})
}
因为调用_load方法后,会出现两个回调函数,因此我们将function(a,$){var num = a.a;$('#J_A').text(num);}标志为callback1,
把this._load(uris, function() { })回调方法标志为callback2.
resolve方法就是解析模块地址的,这里我就不细讲了。
最终var uris = resolve(ids, this.uri)中 的uris被解析成了['https://localhost/test/SEAJS/a.js','http://localhost/test/SEAJS/lib/juqery/1.7.2/juqery-debug.js'],模块路径解析已经完毕。
而接下来将执行this._load
复制代码 代码如下: