web页面优化之动态加载js和文件
关于按需加载js,从而提高页面加载性能:
以京东商品详情页面为例:
首次打开时,会加载一部分js,当下拉滚动条时,会促发事件,从而以jsponp形式异步加载一些js文件,如评论调用的js文件:
http://club.360buy.com/clubservice/newproductcomment-681391-3-0.html?callback=fetchJSON_CommentList(这个链接会被调用,从而加载对应的json数据,再配合实现先好的jsonp处理函数去处理,把结果赋值到对应的位置:
如下是fetchJSON_CommentList实现写好的回调函数
$(".btn-comment").livequery("click", function() { var a = $(this).attr("href"); $.extend(jdModelCallCenter.settings, { clstag1: 0, clstag2: 0, fn: function() { jdModelCallCenter.autoLocation(a) } }); jdModelCallCenter.settings.fn(); return false }); var CommentList = { getData: function(b, c, d) { var f = this, b = b || 0, c = c || 0, d = d, a = "http://club.360buy.com/clubservice/newproductcomment-" + G.sku + "-" + b + "-" + c + ".html"; if (b == 1) { b = 3 } else { if (b == 3) { b = 1 } } window.fetchJSON_CommentList = function(g) { if (!$("#comment .mc").hasClass("loaded")) { if (parseInt(g.CommentSummary.CommentCount) !== 0) { $("#comment").show(); $("#comment .mc").addClass("loaded").html(commentRate_TPL.process(g)) } else { $("#comment").attr("nodata", "true").hide() } $("#comments-list .tab li").each(function() { var j = $("#comments-list .tab li").index($(this)), h = $(this).find("em"); switch (j) { case 0: h.html("(" + g.CommentSummary.CommentCount + ")"); break; case 1: h.html("(" + g.CommentSummary.GoodCount + ")"); break; case 2: h.html("(" + g.CommentSummary.GeneralCount + ")"); break; case 3: h.html("(" + g.CommentSummary.PoorCount + ")"); break; case 4: h.html("(" + g.CommentSummary.ShowCount + ")"); break } }) } f.setItem(d, g, b, c) }; $.getJSONP("http://club.360buy.com/clubservice/newproductcomment-" + G.sku + "-" + b + "-" + c + ".html?callback=fetchJSON_CommentList") }, setItem: function(f, d, a, c) { var j = this, b = f, a = a || 0, c = c || 0, h = f.attr("id"), g = ""; f.html(commentList_TPL.process(d)); switch (h) { case "comment-0": g = "CommentCount"; break; case "comment-1": g = "GoodCount"; break; case "comment-2": g = "GeneralCount"; break; case "comment-3": g = "PoorCount"; break; case "comment-4": g = "ShowCount"; break; default: g = "CommentCount" } $("#commentsPage" + d.Score).pagination(d.CommentSummary[g], { items_per_page: 7, num_display_entries: 5, current_page: c, num_edge_entries: 2, link_to: "#comments-list", prev_text: "\u4e0a\u4e00\u9875", next_text: "\u4e0b\u4e00\u9875", ellipse_text: "...", prev_show_always: false, next_show_always: false, callback: function(k, l) { if (a == 1) { a = 3 } else { if (a == 3) { a = 1 } } j.getData(a, k, b) } }) } };
以下参考:
http://www.aichengxu.com/article/Javascript/610_7.html
s无非就是script标签引入页面,但当项目越来越大的时候,单页面引入N个js显然不行,合并为单个文件减少了请求数,但请求的文件体积却很大。 这时候最好的做法就是按需引入,动态引入组件js和样式,文件load完成后调用callback,运行js。代码还是很简便的 1. 判断文件load完成。加载状态ie为onreadystatechange,其他为onload、onerror if(isie){ Res.onreadystatechange = function(){ if(Res.readyState == 'complete' || Res.readyState == 'loaded'){ Res.onreadystatechange = null; callback(); _self.loadedUi[modelName] = true; } } }else{ Res.onload = function(){ Res.onload = null; callback(); _self.loadedUi[modelName] = true; } Res.onerror = function(){ throw new Error('res error:' + modelName+'.js'); } } 2. 所有组件的命名最好保持一致,callback调用也比较方便。还可以根据需要增加参数比如: requires,依赖于那些文件;style,true || false,是否加载样式,等等。 3. 移除操作也可以有,移除script、style标签、delete组件 (function(window,undefined){ if(!window.ui) { window.ui = {}; } //动态加载ui的js window.bus = { config : { version : window.config.version, cssPath : window.config.resServer + '/css/v3/ui', jsPath : window.config.resServer + '/js/v2/ui' }, loadedUi : {}, readyStateChange : function(){ var ua = navigator.userAgent.toLowerCase(); return ua.indexOf('msie') >= 0; }, loadRes : function(modelName,prames,callback){ var _self = this; var Res = document.createElement(prames.tagName); for(var k in prames){ if(k != 'tagName'){ Res.setAttribute(k,prames[k],0); } } document.getElementsByTagName('head')[0].appendChild(Res); if(this.readyStateChange()){ Res.onreadystatechange = function(){ if(Res.readyState == 'complete' || Res.readyState == 'loaded'){ Res.onreadystatechange = null; callback(); _self.loadedUi[modelName] = true; } } }else{ Res.onload = function(){ Res.onload = null; callback(); _self.loadedUi[modelName] = true; } Res.onerror = function(){ throw new Error('res error:' + modelName+'.js'); } } }, removeUi : function(modelName){ if(!modelName){ return true }; this.loadedUi[modelName] = false; var head = document.getElementsByTagName('head')[0]; var model_js = document.getElementById('J_model_'+modelName + '_js'); var model_css = document.getElementById('J_model_'+modelName + '_css'); if(model_js && model_css){ delete window.ui[modelName]; head.removeChild(model_js); head.removeChild(model_css); return true; }else{ return false; } }, loadUi : function(modelName,callback,setting){ if(!modelName){ return true }; callback = callback || function(){}; if(this.loadedUi[modelName] == true){ callback(); return true } var deafult_setting = { style : true, js : true, requires : [] } for(var key in setting){ deafult_setting[key] = setting[key]; } deafult_setting['style'] === true && this.loadRes(modelName,{ id : 'J_model_'+modelName + '_css', name : modelName, tagName : 'link', type : 'text/css', rel : 'stylesheet', href : this.config.cssPath + '/' + modelName + '.css?v=' + this.config.version }); deafult_setting['js'] === true && this.loadRes(modelName,{ id : 'J_model_'+modelName + '_js', name : modelName, tagName : 'script', type : 'text/javascript', src : this.config.jsPath + '/' + modelName + '.js?v=' + this.config.version },callback); if(deafult_setting.requires.length > 0){ for(var i=0,len = deafult_setting.requires.length;i<len;i++){ this.loadUi(deafult_setting.requires[i]); } } } } })(window) 使用方法 // load comment for feed window.bus.loadUi('new_comment_feed', function(){ window.ui.new_comment_feed($("#J_newsList")); },{ style : false, requires:['emoticon','addFriend'] }); // load new yy ui window.bus.loadUi('yy', function(){ window.ui.yy(options); },{ style:false, requires:['emoticon'] }); // load photoLightbox window.bus.loadUi('photoLightbox', function(){ window.ui.photoLightbox(options.urlAjaxGetFriendPhoto, options.urlCommentOtherPhoto,$("#J_newsList"),options.myUid,options.myName); });