首先大家要知道JavaScript是单线程,解释型,弱类型的语言。
js单线程的原因是为了避免多线程操作dom,引发的并发问题,dom属于基础数据,从多线程上讲,对它的操作要加事物,而js的操作最初就是为了操作dom,总之一句话,凡是能够修改dom的一定得同步
JavaScript异步加载和ajax是没有任何关系的,然后再来看JavaScript时间线的过程。
时间线的步骤
1.创建document对象,开始解析web页面,解析HTML元素和他们的文本内容后添加Element对象和Text节点到文档中,这个阶段document.readyState = “loading”
2.遇到link外部css,创建线程加载,并继续解析文档
3.遇到script外部js,并且没有设置async , defer ,浏览器加载,并阻塞,等待js加载完成并执行该脚本,然后继续解析文档
4.遇到script外部js,并且设置有async,defer 浏览器创建线程加载,并继续解析文档,对于async属性的脚本,脚本加载完成后立即执行(异步禁止使用docuemnt.write())。
5.遇到img标签等,先正常解析dom结构,然后浏览器异步加载src,并继续解析文档
6.当文档解析完成,document.readyState = “interactive”;
7.文档解析完成后,所有设置有defer的脚本会按照顺序执行。
8…当文档解析完成之后,document对象触发DOMContentLoaded事件,这也标志着程序执行从同步脚本执行阶段,转化为事件驱动阶段
9.当所有saync的脚本加载完成并执行后,img等加载完成后,document.readyState = “complete” window对象触发load事件
10.从此,页面以异步响应方式处理用户输入,网络事件等。
总结简化为
1.dom解析中,创建document对象,浏览器开始去解析你的html界面,document.readyState = “loading”
2.当遇到外部资源(外部的js文件,外部的css文件,外部的图片,a标签,iframe标签)的时候,除了script标签中的src(当没有设置异步的属性async,defer)为同步,其余的全部为异步(主线程去调度子线程完成)。有且只有这一个script标签中的src为同步dom解析完成以后 document.readyState = “interactive”
同时触发DOMContentLoaded(jquery中ready方法的封装),这是唯一一个有大写字母的事件名称
3.下载中除了script标签中的,其他的所有外部资源下载完成
4.下载完成以后,document.readyState = “complete”
window触发load事件
DOMContentLoaded、load和jq中的ready函数的区别
load事件在window上有这个事件window.onload这个事件是在dom文档完成渲染完毕之后才会触发,那么如果网速不好的时候,数据没有加载完成,这个事件就不会执行,这样就非常拖浏览器后退的事件
jq中的ready函数,就是对onreadystatechange进行了封装,从效率来看,比window.onload 要高。
而DOMContentLoaded则不同了,这个事件表示的是当Dom解析完毕之后执行,没有浪费浏览器运行效率,但是这个事件只能用addEventListener绑定。但这也不是问题,所以,当我们在head标签里面写JavaScript语句的时候,应该知道用啥了吧
JavaScript异步加载的方案(3种)
1.defer 异步加载 IE才能使用(指创建线程加载,等到DOM结构加载完成后才会执行。里面可以执行内容)
<script src="" defer="defer"></script>
2.async html5中的新属性(加载完就执行,不能执行内容,只能加载外部脚本)
<script src="" async="async"></script>
3.按需加载:创建script标签,设置src属性,变成了异步的。插入到dom中
function loadScript(url,callback){
//创建节点,设置src属性,变成异步
var script = document.createElement("script");
// script.src = url; //考虑到网速快的情况事件事件已经触发完后才将script放入head内(几率很小),为了严谨放入底部
// 进行判断
if(script.readyState){
script.onreadystatechange = function(){ //代码走到这里的时候url就已经下载完成
if(script.readyState == "complete" || script.readyState == "loaded"){
callback()
}
}
}else{
script.onload = function(){
callback()
}
}
script.src = url;
document.head.appendChild(script); // 加入进去代码都执行完成了,就没有用了
}
loadScript("02.js",function(){
test()
})
loadScript("02.js",function(){
fun()
})