前言
作为一前端开发人员,在我们平时的开发过程中,总会有这样的一个问题,就是CSS和JavaScript的加载,到底会不会影响我们的网页的渲染,如果影响,则影响哪些环节。
浏览器的渲染过程
在解决这个问题之前,我们先来看两张图:
我相信这两张图很多做前端的小伙伴都看到过,这两个图,其实是谷歌浏览器和火狐浏览器对我们的网页进行渲染的整个过程。从上图中不难看出都有以下的过程:
- 解析HTML建立DOM树
- 解析CSS规则树构建CSS规则树
- 然后将CSS规则树,然后结合DOM树生成一个渲染树(渲染树和DOM树的区别主要有:渲染树没有header等节点,渲染树中不存在display的为none的节点)
- 接着就根据渲染树,进行排版(就是对各个元素的尺寸,位置进行计算)
- 然后就是根据渲染树中的各个节点显示信息,绘制节点元素的显示信息。
- 浏览器会将各层的信息发送给GPU,GPU会将各层合成(composite),显示在屏幕上。
- 渲染完毕后触发load事件。
load事件与DOMContentLoaded事件
当 DOMContentLoaded 事件触发时,仅当DOM加载完成,不包括样式表,图片,譬如如果有async属性的脚本就不一定加载完成
当 onload 事件触发时,页面上所有的DOM,样式表,脚本,图片都已经加载完成了。
顺序是:DOMContentLoaded -> load
js阻塞
JS 阻塞 DOM 解析(js脚本中有时获取不到元素)
加载 js 文件的时会阻塞 dom 的解析、并且阻塞其它资源(如 css,js 或图片资源)的加载
直到 js 下载、解析、执行完毕后, 才开始继续并行下载其他资源并呈现内容
将 script 标签放在 body 结束标签之前, 虽然也会阻塞页面的呈现,但不会阻塞资源下载(其他资源已经下载完成了),还可以避免因页面没有加载完成而导致获取元素失败的情况
css阻塞
css 加载不会阻塞 dom 树的解析,不会阻塞其它资源(如图片)的加载,但是css 加载会阻塞 dom 树的渲染,也会阻塞 js 文件的执行
css加载不会阻塞DOM树解析(异步加载时DOM照常构建)
浏览器是解析DOM生成DOM Tree,结合CSS生成的CSS Tree,最终组成render tree,再渲染页面,两者分别解析不会互相影响,因而不会阻塞DOM解析
css阻塞render树渲染(渲染时需等css加载完毕,因为render树需要css信息)
如果css加载不阻塞render树渲染的话,那么当css加载完之后,render树可能又得重新重绘或者回流了,这就造成了一些没有必要的损耗。
css会阻塞js的运行
如果脚本的内容是获取元素的样式,宽高等CSS控制的属性,浏览器是需要计算的,也就是依赖于CSS,浏览器也无法感知脚本内容到底是什么,为避免样式获取,因而只好等前面所有的样式下载完后,再执行JS
<script>与<link>同时在头部的话,<script>在上,因为如果<link>的内容下载更快的话,是没影响的,但反过来的话,JS就要等待了,然而这些等待的时间是完全不必要的
注意:当css正在解析时,不会阻塞其它资源(如图片等)的加载,此时若加载了js文件,js文件的执行就会被css阻塞执行,而js又会阻塞html的解析
这就是为何<script>与<link>同时在头部的话,<script>在上可能会更好,因为css若加载时间过长,此时js无法执行,html也无法解析