无阻塞的脚本是创建响应迅速的web应用的第一步,其秘诀就是在页面加载完成后才加载JS,也就是尽量在window.onload事件触发后再下载脚本。
这里对比几种无阻塞加载脚本的方法
一、延迟的脚本
使用script扩展属性defer,由于只有Internet Explorer 支持 defer 属性,所以基本不建议使用这种方式,使用方法为:
<script defer="defer">
二、XMLHttpRequest脚本注入技术
用XHR来下载JS文件,然后通过创建动态script元素将代码注入页面中:
var xhr = new XMLHttpRequest();
xhr.open("get","file.js",true);
xhr.onreadystatechange = function(){
if(xhr.readyState == 4){
//动态添加脚本
var script = document.createElement("script");
script.type = "text/javascript";
script.text = xhr.responseText;
document.body.appendChild(script);
}
}
优点:
1、下载JS但不立即执行,可以把脚本的执行推迟到想执行的时候
2、浏览器通用代码,都能正常工作
缺点:
1、js文件要和请求页面处于相同的域,因此大型web应用通常不会采用该技术。
2、需要HTTP请求
三、动态脚本加载
可以直接封装为一个JavaScript,这里我直接叫loadScript.js
function loadScript(urlS,callback){
//动态加入脚本到
var script = document.createElement("script");
script.type="text/javascript";
if(script.readyState){ //IE
script.onreadystatechange = function(){
if(script.readyState == "loaded" || script.readyState == "complete"){
script.onreadystatechange = null;
callback();
}
}
}else{
script.onload = function(){
callback();
};
}
script.src = urlS;
$("head")[0].appendChild(script);
}
使用方法:
<head>
...
<script src="jq/jquery.min.js"></script>
</head>
<body>
...
<script type="text/javascript">
loadScript("xx.js",function(){
console.log("动态脚本加载完毕,开始执行其脚本里面的方法初始化");
//方法代码内容
});
</script>
</body>
注意:把loadScript函数直接嵌入页面,可以避免产生多一次HTTP请求。
优点:
只需要包含loadScript和一些页面必须脚本代码,下载执行都非常快
对比可以发现,动态脚本技术的是最最佳方案。下面举个具体栗子来看看真实动态脚本加载使用。
我改装一下我之前一篇文章(https://blog.csdn.net/nzzl54/article/details/91040781)写的html
<head>
...
<link rel="stylesheet" type="text/css" href="ztree/css/zTreeStyle/zTreeStyle.css">
<script src="jq/jquery.min.js"></script>
<script src="loadScript.js"></script>
</head>
<body>
<div>选择的是:<input id = "xmtShow" type="text" value = "" style="margin-left:10px;margin-top:10px;width: 160px;"></input></div>
<div class = "tree-content scrollbar" style = "margin-top: 40px;">
<input hidden id="xmtHide" name="xmt">
<input id="xmtQuery" type="text" value="" style="margin-left:10px;margin-top:10px;height:18px;line-height:18px;vertical-align:bottom;">
<input id="xmtQbut" class="xmtQbut" type="button" value="查询">
<input id="xmtCbut" class="xmtQbut" type="button" value="重置">
<ul id="xmtTree" class="ztree scrollbar" style="margin-top:0;">
</ul>
</div>
<script type="text/javascript">
var zNodes = [{id: 1,name: "一级标题1",pId: 0,open:true
}, {id: 2, name: "一级标题2",pId: 0,open:true
}, {id: 3, name: "2.1级标题",pId: 2
}, {id: 4, name: "2.2级标题",pId: 2
}, {id: 5, name: "1.1级标题", pId: 1
}, {id: 6, name: "1.2级标题",pId: 1
}, {id: 7, name: "1.21级标题",pId: 6
}, {id: 8, name: "一级标题3",pId: 0
}, {id: 9, name: "1.22级标题",pId: 6
}, {id: 10, name: "1.221级标题", pId: 9
}, {id: 11, name: "1.2211级标题", pId: 10
}, {id: 12, name: "1.2212级标题", pId: 10 } ];
function setTreeQueryInit(){
var setting = {
view: {
dblClickExpand: false,
showLine: false
},
data: {
simpleData: {
enable: true
}
},
check: {
enable: false,
chkboxType: { "Y": "ps", "N": "s" }
},
callback: {
onClick: myClick,
onCheck: onCheck
}
};
$("#xmtQbut").on('click',function(){//查询项目
var keyword=$("#xmtQuery").val();
var zNodeQuery=[];
if(keyword!=""){
for(var i=0;i<zNodes.length;i++){
if(zNodes[i].name.indexOf(keyword)!=-1){
zNodeQuery.push(zNodes[i]);
}
}
}
$("#xmtTree").empty();
//alert("123");
$.fn.zTree.init($("#xmtTree"), setting, zNodeQuery);
});
$("#xmtCbut").on('click',function(){//重置项目
$("#xmtQuery").val("");
$.fn.zTree.init($("#xmtTree"), setting, zNodes);
});
}
function myClick(event, treeId, treeNode){
console.log(event);
console.log(treeNode);
var deptId = treeNode.id;
console.log(deptId);
var zTree = $.fn.zTree.getZTreeObj(treeId);
var names = "";
var ids = "";
var nodes;
if (zTree.setting.check.enable == true) {
zTree.checkNode(treeNode, !treeNode.checked, false);
nodes = zTree.getCheckedNodes();
} else{
nodes = zTree.getSelectedNodes();
}
for (var i = 0, l = nodes.length; i < l; i++) {
names += nodes[i].name + ",";
ids += nodes[i].id + ",";
}
if (names.length > 0) {
names = names.substring(0, names.length - 1);
ids = ids.substring(0, ids.length - 1);
}
console.log("names = "+names+",ids = "+ids);
$("#xmtHide").attr("value",names);
$("#xmtHide").attr("ids",ids);
$("#xmtShow").attr("value",names);
$("#xmtShow").attr("ids",ids);
}
loadScript("ztree/js/jquery.ztree.all.js",function(){
console.log("ztree/js/jquery.ztree.all.js动态脚本加载完成");
loadScript("plugin/js/selectTreeM.js",function(){
console.log("动态脚本加载完毕,开始执行其脚本里面的方法初始化");
initTree("xmtTree",zNodes,myClick,false);
setTreeQueryInit();
});
});
</script>
</body>
主要是把引入loadScript.js,然后在script中直接使用器提供的函数来进行动态加载
loadScript("ztree/js/jquery.ztree.all.js",function(){
console.log("ztree/js/jquery.ztree.all.js动态脚本加载完成");
loadScript("plugin/js/selectTreeM.js",function(){
console.log("动态脚本加载完毕,开始执行其脚本里面的方法初始化");
initTree("xmtTree",zNodes,myClick,false);
setTreeQueryInit();
});
});
注意:第三种方法非常适用于一个页面加载多个JavaScript的情况,不过需要注意好脚本间的关系,就像上面的selectTreeM.js是需要先加载完毕ztree/js/jquery.ztree.all.js才能执行
增强版库类LazyLoad下载地址:https://github.com/rgrove/lazyload