根据配置文件加载js依赖模块
要求:
根据下面的配置文件
module=[ {'name':'jquery','src':'/js/lib/jquery-1.8.3.js'}, {'name':'swfobject','src':'/js/utils/swfobject.js'}, {'name':'fancybox','src':'/js/jquery/jquery.fancybox.js','require':['jquery']}, {'name':'uploadify','src':'/js/utils/uploadify.js','require':['swfobject']}, {'name':'jqform','src':'/js/jquery/jquery.form.js','require':['jquery']}, {'name':'register','src':'/js/page/reg.js','require':['jqform']}, {'name':'login','src':'/js/page/login.js','require':['fancybox','jqform']}, {'name':'upload','src':'/js/page/upload.js','require':['fancybox','jqform','uploadify']} ]
写一个函数
defgetfiles(name)
返回加载某个name指定的页面,要加载的js文件列表,有依赖的要先加载
小菜解法
此题粗看起来很简单,实则不然。
难点在于依赖模块的加载时机。假如有这样的依赖关系:A-B&C、B-C,A模块依赖B模块和C模块,同时B模块又依赖了C模块,总不能让C加载两次吧!
小菜给出的这个解法,只是一个思路,肯定有比这更好的算法,小菜觉得可以用二叉树之类的算法解决,但小菜不会呀~~~
此算法没有考虑循环依赖的情景。
代码如下:
/** *不考虑循环依赖 *@type{Function} */ varloadModule=(function(){ /** *业务逻辑封装 *@type{{chainHead:{},chainCurrent:{},srcCache:{},main:main,load:load,findModule:findModule}} */ varlogics={ chainHead:{}, //链表头 chainCurrent:{}, //链表当前节点 srcCache:{}, //modulesrc缓存 /** *对外接口 *@parammodules 配置对象 *@paramname 模块名称 *@returns{Array}依赖模块列表,按照加载先后顺序排列 */ main:function(modules,name){ varnameArray=[], //模块名称列表 srcArray=[], //依赖模块列表 nameStr="", //模块名称字符串集 repeatRegex=/(^|)([\w]+).*\2/, //模块名称去重正则 i=0; //粗略加载所有依赖模块 this.load(modules,name) //构造模块名称字符串集 this.chainCurrent=this.chainHead; while(this.chainCurrent.next){ nameArray.push(this.chainCurrent.name); this.chainCurrent=this.chainCurrent.next; } nameStr=nameArray.join("")+""; //统一标准,末尾补一个空格 //依赖模块去重 while(repeatRegex.exec(nameStr)){ nameStr=nameStr.replace(repeatRegex,function(g0,g1,g2){ returng0.substring(0,(g0.length-g2.length)); }); } nameStr=nameStr.substring(0,(nameStr.length-1)); //去掉补充的多余空格 //依赖模块名称转换为模块路径 nameArray=nameStr.split(""); for(i=0;i<nameArray.length;i++){ srcArray.push(this.srcCache[nameArray[i]]); } returnsrcArray; }, /** *递归加载模块 *@parammodules 配置对象 *@paramname 模块名称 */ load:function(modules,name){ varnode={}, module=this.findModule.call(modules,"name",name), i=0; //判断模块是否存在 if(!module){ throwError("依赖模块"+name+"未找到"); } //构造模块依赖链表 node.name=name; // node.src=module.src; this.srcCache[name]=module.src; node.next=this.chainHead; this.chainHead=node; //递归依赖 if(module.require&&module.require.length){ for(i=0;i<module.require.length;i++){ this.load(modules,module.require[i]); } } }, /** *根据指定属性名称和属性值查找模块 *@paramname 属性名称 *@paramvalue 属性值 *@returns{*} */ findModule:function(name,value){ vararray=this, item={}, i=0; //遍历模块 for(i=0;i<array.length;i++){ item=array[i]; //获取指定模块 if(item&&item[name]===value){ returnitem; } } //找不到返回null returnnull; } }; //暴露对外接口 returnfunction(){ returnlogics.main.apply(logics,arguments); }; }()); /** *TestUsecase *@type{*[]} */ varmodules=[ {'name':'jquery','src':'/js/lib/jquery-1.8.3.js'}, {'name':'swfobject','src':'/js/utils/swfobject.js'}, {'name':'fancybox','src':'/js/jquery/jquery.fancybox.js','require':['jquery']}, {'name':'uploadify','src':'/js/utils/uploadify.js','require':['swfobject']}, {'name':'jqform','src':'/js/jquery/jquery.form.js','require':['jquery']}, {'name':'register','src':'/js/page/reg.js','require':['jqform']}, {'name':'login','src':'/js/page/login.js','require':['fancybox','jqform']}, {'name':'upload','src':'/js/page/upload.js','require':['fancybox','jqform','login','uploadify']} ]; console.log(loadModule(modules,"upload"));