异步加载与加载时间线
页面的渲染过程DOMTree + CSSTree = RenderTree;
根据HTML结构生成DOM Tree、CSS生成CSSTree,DOM和CSSTree 整合形成RenderTree
根据RenderTree开始渲染和展示,遇到srcipt标签时,会执行并阻塞渲染 因为js有权利改变DOM结构,避免冲突从上到下执行。
布局(Layout)和绘制(Paint),重绘(repaint)和重排(reflow/回流)
1)重绘:根据元素的新属性重新绘制,使元素呈现新的外观
2)重排:当渲染树中的一部分因为元素的规模尺寸,布局,隐藏等改变而需要重新构建(效率极低)
3)重排必定会引发重绘,但重绘不一定会引发重排。
JS的同步加载与异步加载
同步加载:又被称为阻塞模式,会阻止浏览器的后续处理,停止后续的解析,只有当当前加载完成,才能进行下一步操作。所以默认同步执行才是安全的。但这样如果js中有输出document内容、修改dom、重定向等行为,就会造成页面堵塞。所以一般建议把<srcipt>
标签放在<body>
结尾处,这样尽可能减少页面阻塞。
异步加载:也称非阻塞加载,浏览器在下载执行js的同时,还会继续进行后续页面的处理。通俗的说,就是在执行过程同时加载,通常会使图片之类重要性较次的东西,可以先忽略掉,,如果另一个线程完成加载了,在贴上去,就是异步。
主要有三种方式实现异步加载:
(1)、defer在DOM文档解析完成之后才执行js文件,I在IE低版本中 defer 可以让script请求的文件异步加载。
<script defer> //IE
console.log("hello");
</script>
(2)async 针对其他浏览器,加载完就执行,只能加载外部脚本。
<script src = "load.js" async></script>
(3)创建一个script标签,插入DOM中,加载完毕后 就callback,兼容性是最好的。
<script type = "text/javascript">
var script = document.createElement("script");//创建一个script标签
script.type = "text/javascript";//添加属性并赋值
if(script.readyState){//判断此时的状态
script.onreadystatechange = function(){//onreadystatechange检测状态码
//处理兼容性问题 complete loaded 都表示script加载完成
if(script.readyState == "complete" || script.readyState= "loaded"){
obj[callback]();
}
}
}else{ //chrome高版本
sctipt.onload = function(){ //资源事件监测dom.js下载完毕就触发此事件
obj[callback]();
}
}
script.src= url;
document.head.appendChild(script);//挂在到DOM树上,执行代码
}
</script>
加载时间线
1.创建Document对象,开始解析web页面,解析HTML元素和他们的文本内容后添加Element对象和Text节点到文档中,这个阶段document.readyState.
= ‘loading’. 准备进入加载阶段。
2.遇到link外部css,创建线程加载,并继续解析文档。
3.遇到script外部js,并且没有设置async、defer,浏览器加载,并阻塞,等待js加载完成并执行该脚本,然后继续解析文档。
(-解析的同步js文件-)
4.遇到script外部js,并且设置有async、defer,浏览器创建线程加载,并继续解析文档。对于async属性的脚本,脚本加载完成后立即执行。
(-异步禁止使用document.write(),因为document.write()有可能会清空文档流 chrome浏览器禁止了外部异步的js文件使用document.write()方法-)
5.遇到img等,先正常解析dom结果,然后浏览器异步加载src(图片资源),并继续解析文档。
6.当文档解析完成,document.readyState = ‘interactive’.准备进入交互阶段。
7.文档解析完成后,所有设置有defer的脚本按照顺序执行。
8.document对象触发DOMContentLoaded事件,这也标志着程序执行从同步脚本执行阶段,转换为事件驱动阶段。(注意,这里仍然可能会有异步脚本未完成加载。)
9.当所有async的脚本的加载完成并执行后、img等加载完成后,document.readyState =
‘complete’,文档、脚本、资源此时全部完成 window对象触发load事件。
(页面所有的内容解析完成 加载完成)
10.,以异步响应式处理用户输入、网络事件等。
综上,JS最好放在文档下面加载,不会阻塞页面的正常解析;工具类的JS可以放在head里面,但是要异步加载;window.onload事件是要等所有加载完成后才触发,效率最低,最好把主程序代码放到文档解析完成后开始执行。