今天被问到了如何异步加载js,听到这句话我内心是拒绝的,啥玩意儿?js也要用异步加载不是引入了就行了,也没见速度变慢啊。后来仔细查询了一下,才发现自己原来还是太年轻了。
因为之前自己写的加载的都是本地js,或者是并没有复杂逻辑运算的js,导致看不出来太大问题,查完资料后,要将不会的记在这里,当作学习的资料室。
1,什么是异步加载js
使js文件脱离html解析的瀑布流加载,从而使js可以并行下载。
2,为什么要异步加载
一般写法将js放在head中,而且默认方式是同步加载,这就会导致在进行js加载的过程中,无法在其加载完成前对后续的内容进行操作,造成页面内阻塞,对用户体验很不友好。
3,如何异步加载
之前我们的写法就是把外部js或js放在body后或内部js放在body结束标签之前,这样会使至少先把一些基本内容加载出来而不会让人等太久,值得注意的是js中一般包含对dom的操作,如果放在body前,就可能出现空白或闪烁,而且js如果放在body内即结束标签之前,则无法获得onload和readystate,需要好好分析。
(1)、而比较常用的写法是动态的添加一个script标签,叫做Script DOM Element:
//立即执行函数
(function(){
//创建一个script标签
var scriptTag = document.creatElement("script");
//h4前type必须加上,h5可以不加
scriptTag.type = "text/javascript";
//h5新增的,用这种方法可以不写
scriptTag.async = true;
//你的地址
scriptTag.src = "js地址";
//获取head标签
var headTag = document.getElementsByTagName("head")[0];
//在已有子节点前插入该标签,其实也可以用appendChild
headTag.insertBefore(scriptTag, headTag.firstChild);
})()
但是这个函数又放在哪里呢,我一时间没查到,不过想想应该是放在head中的,毕竟它也是同步加载的。但是这种方法有个问题,它会阻止onload函数的触发,但是我们有很多时候都需要使用这个函数来渲染一些其他东西,所以可以将该函数也放在onload中:
(function(){
//兼容ie,因为ie的window上没有addEventListener
if(window.attachEvent){
window.attachEvent("load", asyncLoad);
//非ie
}else{
window.addEventListener("load", asyncLoad);
}
var asyncLoad = function(){
var scriptTag= document.createElement('script');
scriptTag.type = 'text/javascript';
scriptTag.async = true;
scriptTag.src ="你的地址";
var headTag= document.getElementsByTagName('head')[0];
headTag.insertBefore(scriptTag, headTag);
}
)();
(2)、defer
该属性是h5新属性,只有ie可以用,主要可以延迟脚本的执行;
有3点需要注意:
1. defer
只适用于外联脚本,如果script
标签没有指定src
属性,只是内联脚本,不要使用defer
2. 如果有多个声明了defer
的脚本,则会按顺序下载和执行
3. defer
脚本会在DOMContentLoaded
和load
事件之前执行
(3)、async
该属性声明外部js的异步加载;
也是3点:
1. 只适用于外联脚本,这一点和defer
一致
2. 如果有多个声明了async
的脚本,其下载和执行也是异步的,不能确保彼此的先后顺序
3. async
会在load
事件之前执行,但并不能确保与DOMContentLoaded
的执行先后顺序
这两个属性搬运自https://blog.csdn.net/liuhe688/article/details/51247484 ,写的十分之详细,可以好好看看加深理解。
其中参考了https://www.cnblogs.com/hq233/p/7102549.html ,滥好人写的讲解,学习到了很多。