为什么要异步加载
浏览器下载除JS外的资源时,会并行下载,以提高性能。但下载JS脚本时,会禁止并行下载(称为脚本阻塞Scripts Block Downloads)。浏览器遇到JS时,必须等JS下载,解析,执行完后,才能继续并行下载下一个资源。原因是JS可能会改变页面或改变JS间的依赖关系,例如A.js中用document.write改变页面,B.js依赖于A.js。因此要严格保证顺序,不能并行下载。
因此不推荐将JS放到<head>标签里,浏览器遇到<script>标签会下载,解析,执行完脚本后,才继续处理剩余的页面部分。
为了避免白屏,通常的建议是将JS放到<body>标签底下,可以有最佳的用户体验,你可以点击例子页面试一下。如果你放到了<body>标签的上部,因为脚本阻塞,可能会影响用户体验。例子中位于<body>上部的JS耗时2s,因此位于JS下面的两张img图片,会等2s后才开始加载。
将JS放在<body>底下的建议没有错,几乎成了前端的普世规则。但对于追求极致用户体验的站点,或大型网站来说,这还不够。
异步加载的方法
Dynamic Script Element动态脚本元素
该技术不但简单,而且通用,且可以跨域,应该成为你的首选
var script = document.createElement('script'); //创建script标签
script.type = "text/javascript";
script.src = "A.js";
document.getElementsByTagName('head')[0].appendChild(script); //塞进页面
当JS下载完毕后,就会立即执行。如果多个JS间有依赖关系,一下载完马上执行可能会出现error。因此通常来说你应该将有依赖关系的JS合并成一个文件,虽然合并后JS文件会变大,但由于是异步下载,你几乎不会有什么损失。
如果实在不方便将有依赖关系的文件合并。你需要自己指定先后顺序,通过监听load事件(IE是onreadystatechange)来确保依次加载脚本:
function loadScript(url, 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 { //Others
script.onload = function(){
callback();
};
}
script.src = url;
document.getElementsByTagName("head")[0].appendChild(script);
}
//严格确保A->B->C,依次下载脚本文件
loadScript("A-delay.js", function(){
loadScript("B-delay.js", function(){
loadScript("C-delay.js", function(){
console.log("All files are loaded!");
});
});
});
Script async
HTML5里为script标签里新增了async属性,用于异步加载脚本
<script type="text/javascript" src="alert.js" async="async"></script>
1.async属性是HTML5新增属性,需要Chrome、FireFox、IE9+浏览器支持
2.async属性规定一旦脚本可用,则会异步执行
3.async属性仅适用于外部脚本
4.此方法不能保证脚本按顺序执行
Script defer
script标签里可以设置defer,表示延迟加载脚本:
<script type="text/javascript" src="alert.js" defer="defer"></script>
1.defer属性规定是否对脚本执行进行延迟,直到页面加载为止
2.如果脚本不会改变文档的内容,可将defer属性加入到<script>标签中,以便加快处理文档的速度
3.兼容所有浏览器
4.此方法可以确保所有设置了defer属性的脚本按顺序执行
更多
更多方法见
异步加载JS脚本
网友评论