现代浏览器加载资源分析
网页加载流程
- 浏览器发送请求,拿到HTML资源,并开始解析。
- 解析过程中,遇到link标签,浏览器发出对CSS文件的请求,。
- 当浏览器解析到
<body>
标签,并且CSS文件已经下载到手,可以开始渲染页面。 - 当浏览器遇到
<script>
标签,阻塞页面的解析以及其他资源的下载,直到JS文件加载执行完毕 - 浏览器完成解析HTML页面。
这是常规的浏览器加载、解析资源流程。
注意
- 在页面渲染过程中,如果遇到其他外部资源,如
<img>
图片,是不阻塞渲染的,当服务器返回图片资源时,浏览器再回过头来重新渲染这部分代码。 - 浏览器解析过程是边解析html生成局部DOM树,边生成部分render树并展示出来,这么做是为了让用户能更快的看到页面,而不是一进来先出现一会儿白屏现象。
- 加载JS文件阻塞页面解析的原因是为了防止JS修改了DOM树,引起DOM树不稳定,需要重新渲染的情况(如
document.write
)。如果JS代码有对页面进行修改,如隐藏某个<div>
元素,则浏览器会重新渲染这部分代码。 - CSS会阻塞JS的执行(内嵌CSS不会)。以防JS计算用到了CSS样式,而CSS此时不存在导致的错误(如
var width = $('#id').width()
)(在执行CSS解析时,文档会暂停解析文档,Firefox 在样式表加载和解析的过程中,会禁止所有脚本。而对于 Webkit 而言,仅当脚本尝试访问的样式属性可能受尚未加载的样式表影响时,它才会禁止该脚本。)(浏览器会根据link和script标签的顺序解析,如果script在前,link在后,则在JS中计算样式会拿到未被CSS解析过的样式值。) - JS的执行依赖加载顺序,如果出现同名函数,后面会覆盖前面。
优化
- 尽量将CSS文件写在
<header>
中,将JS文件写在</body>
之前。 - 在现代浏览器中,会对资源做
prefetch
优化(此时理论上来讲可以忽略第一条),开启一个新线程,对JS和CSS进行预加载,这意味着将不会再出现阻塞加载的情况,理论上 JS 和 CSS 的下载时机都非常优先,和位置无关。但是要注意的是,资源只是提前加载,并不会执行。 - 在新的HTML5规范中,
script
标签有两个新增属性,分别是defer
和async
。defer与async的区别是:前者要等到整个页面正常渲染结束,才会执行;后者一旦下载完,渲染引擎就会中断渲染,执行这个脚本以后,再继续渲染。一句话,defer是“渲染完再执行”,async是“下载完就执行”。另外,如果有多个defer脚本,会按照它们在页面出现的顺序加载,而多个async脚本是不能保证加载顺序的。
- defer 并行加载JS,当页面全部加载完成时再按顺序执行JS脚本。
- async 将不会依赖于任何js和css的执行,此js下载完成后立刻执行,不保证按照书写的顺序执行。因为async=”true”属性会告诉浏览器,js不会修改dom和样式,故不必依赖其它的js和css。当浏览器解析到script标签时,会继续往下解析HTML,并同时并行下载JS文件,当JS下载完成,则暂停解析HTML,执行JS文件。JS执行完毕后,浏览器恢复解析HTML页面。不过需要注意的是,哪个JS文件先现在完成,就先执行哪个脚本,而不依赖于JS文件的顺序。另外,使用async属性的脚本文件中,不应该使用document.write方法。
- 在webkit和FireFox中,有预解析优化。当执行脚本时,另一个线程解析剩下的文档,并加载后面需要通过网络加载的资源。这种方式可以使资源并行加载从而使整体速度更快。需要注意的是,预解析并不改变Dom树,它将这个工作留给主解析过程,自己只解析外部资源的引用,比如外部脚本、样式表及图片。
- 合理的运用一些build工具,如gulp,webpack等。
- 减少http请求,外部域名访问。
- 合理使用缓存机制。
- 优化页面资源加载顺序,不需要第一时间显示的资源可以放到后面去加载。
- DOM 的多个读操作(或多个写操作),应该放在一起。
- 合并多个DOM操作,可以先将要修改的节点clone下来,整体修改完后再一次性修改DOM,减少渲染次数。
- 用工具优化图片资源,小图片可以用base64编码
呈现引擎基本流程。 解析HTML构建DOM树-> 渲染树构建 -> 布局渲染树 -> 绘制渲染树
详情关注博客 https://mmmaming.github.io/
版权声明:本文为u014240243原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。