可以一句概括为利用动态script实现异步回调,每个模块位于独立的文件中,自行处理依赖。
//核心模块,包含加载逻辑,最下面的query模块其实也没有必要用use方法包含起来,单纯让逻辑更清晰些。
//总之,除了加载逻辑外,其他模块都写在use方法的回调函数中。模块与一般的回调函数的区别是,模块只能
//执行一次(因为没有必要重复执行),因此我们要在其里面使用arguments.callee._attached = true标识它
//另,对于文件的重复加载对策是使用一个hash来存在这些已加载的模块,这个由loaded方法来处理
var dom = window.dom = {genScriptNode : function() {var script = document.createElement("script");script.type = "text/javascript";script.charset = "utf-8";return script;},head:function(){return document.getElementsByTagName("head")[0]},env:{ loaded:{}, //已经加载的文件hashqueue:[] //待处理列队},//使用模块use: function(name, callback, config) {config = config || {};var depends = config.use || [],queue = dom.env.queue,i,item;//去掉“dom.”前缀,防止混乱name = name.indexOf("dom.") === 0 ? name.slice(4):nameif(!name)//必须指定模块名return this;if(queue.length){//配置列队//如果是加载一个模块过程中需要加载其他模块,我们需要首先执行那些依赖模块,//因此顺序都是倒着加入队列queue.unshift(callback);queue.unshift(name);i = depends.length;while (i--) {//添加所有依赖queue.unshift(depends[i]);}}else{//配置列队for(i=0;item = depends[i++];){//添加所有依赖queue.push(item);}//添加模块名,用于可能的文件加载queue.push(name);//添加回调函数(也有可能是模块本身)queue.push(callback);}dom._loadNext();//开始执行列队return this;},//用于标识此模块所在的JS文件已经被加载,并清除timeoutIDloaded:function(name){dom.env.loaded[name] = true;var timeoutID = dom.namespace("dom."+name,true).timeoutID;timeoutID && clearTimeout(timeoutID)},//name为模块名,create不存在此属性是否创建一个空对象namespace:function(name,create,context){var parts=name.split("."),obj = context || window;for(var i=0, p; obj && (p=parts[i]); i++){if(i == 0 && this[p]){p = this[p];}obj = (p in obj ? obj[p] : (create ? obj[p]={} : undefined));}return obj; },//加载文件,装配新模块或执行回调_loadNext:function(){var env = dom.env, queue = env.queue,loaded = env.loaded;if(queue.length){var item = queue.shift();if(typeof item === "string" ){if(!loaded[item]){//如果此模块所在的JS文件还没有加载,则加载它 var module = "dom."+item,url;//处理dom.node(http://www.cnblogs.com/rubylouvre/dom/node.js)的情形var _u = module.match(/\(([^)]+)\)/);url = _u && _u[1] ? _u[1] : dom.getBasePath()+"/"+ module.replace(/\./g, "/") + ".js";var script = dom.genScriptNode();script.src = urldom.head().appendChild(script);var scope = dom.namespace(module,true)scope.timeoutID = setTimeout(function(){alert("Fail to load module '"+module+"'!")},1000)//让将要加载JS文件中的函数调用 dom._loadNext}else{//否则跳过,继续处理下一个dom._loadNext();}//如果是函数,可能是普通的回调函数,也可能是模块本身}else if(typeof item === "function"){if(!item._attached){//如果是模块则只会执行一次item();}dom._loadNext();}}},//获取核心模块所在的JS文件所在的文件夹路径getBasePath : function(){ var result = "",m;try{a.b.c();}catch(e){if(e.fileName){//firefoxresult = e.fileName;}else if(e.sourceURL){//safariresult = e.sourceURL;}else if(e.stacktrace){//opera9m = e.stacktrace.match(/\(\) in\s+(.*?\:\/\/\S+)/m);if (m && m[1])result = m[1]}else if(e.stack){//chrome 4+m= e.stack.match(/\(([^)]+)\)/)if (m && m[1])result = m[1]}}if(!result){//IE与chrome4- opera10+var scripts = document.getElementsByTagName("script");var reg = /dom([.-]\d)*\.js(\W|$)/i,srcfor(var i=0, el; el = scripts[i++];){src = !!document.querySelector ? el.src:el.getAttribute("src",4);if(src && reg.test(src)){result = srcbreak;}}}return result.substr( 0, result.lastIndexOf('/'));}
};dom.loaded("query") ;
dom.use("query",function(){//☆☆☆这里不会使用动态标签来加载它,因为它已调用了loaded方法,它只会顺势执行回调函数arguments.callee._attached = true;alert("query加载成功")
},{use:["behaviour"]
});
node模块
//位于/dom/node.js
dom.loaded("node");
dom.use("node",function(){arguments.callee._attached = true;dom.node1 ="开始装载node模块"
});
event模块
//位于/dom/event.js
dom.loaded("event");
dom.use("event",function(){arguments.callee._attached = true;dom.event1 = "ddd"alert("event模块已装载成功")
})
behaviour模块
//位于/dom/behaviour.js
dom.loaded("behaviour");
dom.use("behaviour",function(){arguments.callee._attached = true;alert("behaviour模块已装载成功")
})
前台调用
window.οnlοad=function(){dom.use("event", function(){//★★★这里会使用动态标签,加载JS文件,装载event模块与执行回调函数alert(dom.event1)});}
没有空间,恕不演示了!