关于js按需加载的依赖问题
最近在做一个项目,作者使用jquery,由于原始jquery库中没有js按需加载,因此作者自己写了一个js按需加载的方法,方法如下
loadScript:function(urlArr,callBack){ var _this = this; window.baseUrl = window.baseUrl || ''; urlArr = $.map(urlArr,function(n){ return window.baseUrl+n; }); var scriptList = document.getElementsByTagName("script"); for (i = 0,max = scriptList.length; i < max; i++) { if(urlArr.length===0){ if($.isFunction(callBack)){ callBack.call(window); } return; } var index = $.inArray(scriptList[i].src,urlArr); if(index!==-1){ urlArr.splice(index,1); } } if($.isArray(urlArr)){ var length = urlArr.length; if(length===0){ if($.isFunction(callBack)){ callBack.call(window); } return; } else{ loadOne(urlArr,callBack); } } function loadOne(urlArr,callBack){ var url = urlArr.shift(); var script = document.createElement("script"); script.type="text/javascript"; script.src = url; script.onload = script.onreadystatechange=function(){ if(urlArr.length===0){ if($.isFunction(callBack)){ if (this.readyState && this.readyState == "loading") return; callBack.call(window); } return; } else{ loadOne(urlArr,callBack); } }; script.onerror=function(){ throw new Error("load script:"+url+" error"); }; var scriptList = document.getElementsByTagName("script"); document.getElementsByTagName("head")[0].appendChild(script); } },
此方法的两个参数,第一个是js的数组,第二个为回调函数,此方法在高版本浏览器中相当正常(包括,IE10,chrome,火狐),但是在ie9一下包括ie9就出现问题,在script的onreadystatechange中出不去,一直在循环,然后作者很郁闷就询问了一个公司的大神,结果大神出手,便出现下面代码
function loadScript(urlArr,callBack){ var _this = this; window.baseUrl = window.baseUrl || ''; urlArr = $.map(urlArr,function(n){ return window.baseUrl+n; }); var scriptList = document.getElementsByTagName("script"); for (i = 0,max = scriptList.length; i < max; i++) { if(urlArr.length===0){ if($.isFunction(callBack)){ callBack.call(window); } return; } var index = $.inArray(scriptList[i].src,urlArr); if(index!==-1){ urlArr.splice(index,1); } } if($.isArray(urlArr)){ var length = urlArr.length; if(length===0){ if($.isFunction(callBack)){ callBack.call(window); } return; } else{ loadOne(urlArr,callBack); } } function loadOne(urlArr,callBack){ var url = urlArr.shift(); var script = document.createElement("script"); script.type="text/javascript"; script.src = url; var exec = function(){ if(urlArr.length===0){ if($.isFunction(callBack)){ callBack.call(window); } } else{ loadOne(urlArr,callBack); } }; if(script.attachEvent){ script.attachEvent('onreadystatechange',function(){ if(script.readyState == 'loaded' || script.readyState == 'complete') { exec(); script.detachEvent('onreadystatechange',arguments.callee); } }); } else { script.addEventListener('load',function(){ exec(); script.removeEventListener('load',arguments.callee,false); },false); } /* script.onload = script.onreadystatechange=function(){ if(urlArr.length===0){ if($.isFunction(callBack)){ if (this.readyState && this.readyState == "loading") return; callBack.call(window); } return; } else{ loadOne(urlArr,callBack); } }; */ script.onerror=function(){ throw new Error("load script:"+url+" error"); }; var scriptList = document.getElementsByTagName("script"); document.getElementsByTagName("head")[0].appendChild(script); } }
这两版代码的不同之处在于,大神的代码在执行完递归方法后,清除掉了script的onreadystatechange事件,如此便不会出现函数在scirpt的onreadystatechange事件中跑不出来了,但是笔者还是觉得不甘心,又在网上查了好久,也查了不少东西建议使用attachEvent 请记得 对于ie6 任何非 attachEvent方式注册的事件 (除硬编码写到html中的) 都会引起ie6 无法挽回的 跨页内存泄露. 至于多少 就看回调函数 所在闭包 中的数据量了. 作用域链 越深 受影响的东西 就越多...危害也就越大. 这篇文章中就讲明了这种方法的一些弊端,但是实在没办法,笔者只能舍弃小家为大家,放弃了ie6的速度而是选择其他浏览器的按需加载js。
并且在写这个方法中,笔者发现大神朋友的方法中有一句arguments.callee,从来没用过的方法,百度一下,才发现原来这个是获取参数的原函数对象,大神犀利!!!至此这个方法引起的风波也告一段落了,但是本以为自己的js已经算是不错了,却发现还真是差得远,编程思想还是差得远,遇见棘手问题解决还是与大神有差距,需要努力啊!!!!