根据配置文件加载js依赖模块(JavaScript面试题)

面试题目

 

根据下面的配置文件
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']}
]


写一个函数 

def getfiles(name)

返回 加载某个name指定的页面,要加载的js文件列表,有依赖的要先加载

 

小菜解法

 

     此题粗看起来很简单,实则不然。

     难点在于依赖模块的加载时机。假如有这样的依赖关系:A-B&C、B-C,A模块依赖B模块和C模块,同时B模块又依赖了C模块,总不能让C加载两次吧!

     小菜给出的这个解法,只是一个思路,肯定有比这更好的算法,小菜觉得可以用二叉树之类的算法解决,但小菜不会呀~~~

     此算法没有考虑循环依赖的情景。

     代码如下:

  1 /**
  2  * 不考虑循环依赖
  3  * @type {Function}
  4  */
  5 var loadModule = (function(){
  6     /**
  7      * 业务逻辑封装
  8      * @type {{chainHead: {}, chainCurrent: {}, srcCache: {}, main: main, load: load, findModule: findModule}}
  9      */
 10     var logics = {
 11         chainHead: {},     //链表头
 12         chainCurrent: {},  //链表当前节点
 13         srcCache: {},      //module src 缓存
 14         /**
 15          * 对外接口
 16          * @param modules  配置对象
 17          * @param name  模块名称
 18          * @returns {Array} 依赖模块列表,按照加载先后顺序排列
 19          */
 20         main: function(modules, name){
 21             var nameArray = [],  //模块名称列表
 22                 srcArray = [],   //依赖模块列表
 23                 nameStr = "",    //模块名称字符串集
 24                 repeatRegex = /(^| )([\w]+ ).*\2/,  //模块名称去重正则
 25                 i = 0;
 26 
 27             //粗略加载所有依赖模块
 28             this.load(modules, name)
 29 
 30             //构造模块名称字符串集
 31             this.chainCurrent = this.chainHead;
 32             while(this.chainCurrent.next){
 33                 nameArray.push(this.chainCurrent.name);
 34                 this.chainCurrent = this.chainCurrent.next;
 35             }
 36             nameStr = nameArray.join(" ") + " ";  //统一标准,末尾补一个空格
 37 
 38             //依赖模块去重
 39             while(repeatRegex.exec(nameStr)){
 40                 nameStr = nameStr.replace(repeatRegex, function(g0, g1, g2){
 41                     return g0.substring(0, (g0.length - g2.length));
 42                 });
 43             }
 44             nameStr = nameStr.substring(0, (nameStr.length - 1));  //去掉补充的多余空格
 45 
 46             //依赖模块名称转换为模块路径
 47             nameArray = nameStr.split(" ");
 48             for(i = 0; i < nameArray.length; i++){
 49                 srcArray.push(this.srcCache[nameArray[i]]);
 50             }
 51 
 52             return srcArray;
 53         },
 54         /**
 55          * 递归加载模块
 56          * @param modules  配置对象
 57          * @param name  模块名称
 58          */
 59         load: function(modules, name){
 60             var node = {},
 61                 module = this.findModule.call(modules, "name", name),
 62                 i = 0;
 63             //判断模块是否存在
 64             if(!module){
 65                 throw Error("依赖模块 " + name +" 未找到");
 66             }
 67             //构造模块依赖链表
 68             node.name = name;
 69 //            node.src = module.src;
 70             this.srcCache[name] = module.src;
 71             node.next = this.chainHead;
 72             this.chainHead = node;
 73             //递归依赖
 74             if(module.require && module.require.length){
 75                 for(i = 0;i < module.require.length; i++){
 76                     this.load(modules, module.require[i]);
 77                 }
 78             }
 79         },
 80         /**
 81          * 根据指定属性名称和属性值查找模块
 82          * @param name  属性名称
 83          * @param value  属性值
 84          * @returns {*}
 85          */
 86         findModule: function(name, value){
 87             var array = this,
 88                 item = {},
 89                 i = 0;
 90             //遍历模块
 91             for(i = 0; i < array.length; i++){
 92                 item = array[i];
 93                 //获取指定模块
 94                 if(item && item[name] === value){
 95                     return item;
 96                 }
 97             }
 98 
 99             //找不到返回null
100             return null;
101         }
102     };
103 
104     //暴露对外接口
105     return function(){
106         return logics.main.apply(logics, arguments);
107     };
108 }());
109 
110 
111 /**
112  * Test Usecase
113  * @type {*[]}
114  */
115 
116 var modules=[
117     {'name':'jquery','src':'/js/lib/jquery-1.8.3.js'},
118     {'name':'swfobject','src':'/js/utils/swfobject.js'},
119     {'name':'fancybox','src':'/js/jquery/jquery.fancybox.js','require':['jquery']},
120     {'name':'uploadify','src':'/js/utils/uploadify.js','require':['swfobject']},
121     {'name':'jqform','src':'/js/jquery/jquery.form.js','require':['jquery']},
122     {'name':'register','src':'/js/page/reg.js','require':['jqform']},
123     {'name':'login','src':'/js/page/login.js','require':['fancybox','jqform']},
124     {'name':'upload','src':'/js/page/upload.js','require':['fancybox','jqform','login','uploadify']}
125 ];
126 
127 console.log(loadModule(modules, "upload"));

 

posted @ 2014-11-24 17:21  杨元  阅读(1561)  评论(0编辑  收藏  举报