大家都知道,css文件放头部,js文件放body最底部,可是大家知道其中的原理吗?
要明白上述问题,我们需要知道是什么在阻塞页面的渲染?
一:回顾浏览器渲染流程
1.浏览器开始解析目标HTML文件,执行流的顺序为自上而下。
2.HTML解析器将HTML结构转换为基础的DOM(文档对象模型),构建DOM树完成后,触发DomContendLoaded事件。
3.CSS解析器将CSS解析为CSSOM(层叠样式表对象模型),一棵仅含有样式信息的树。
4.CSSOM和DOM开始合并构成渲染树,每个节点开始包含具体的样式信息。
5.计算渲染树中个各个节点的位置信息,即布局阶段。
6.将布局后的渲染树显示到界面上。
二:CSS是否会阻塞DOM的解析?
由上文可见,DOM树解析跟CSSOM解析,是互不影响的,两个并行过程,因此,CSS不会阻塞DOM的解析。
三:CSS是否会阻塞DOM的渲染?
根据以上的流程,可以知道,当cssom还没构建完成时,页面是不会渲染到浏览器界面的(渲染时需等css加载完毕,因为render树需要css信息),因此CSS会阻塞DOM的渲染。
其实我觉得,这可能也是浏览器的一种优化机制。因为你加载css的时候,可能会修改下面DOM节点的样式,如果css加载不阻塞DOM树渲染的话,那么当css加载完之后,DOM树可能又得重新重绘或者回流了,这就造成了一些没有必要的损耗。所以我干脆就先把DOM树的结构先解析完,把可以做的工作做完,然后等你css加载完之后,在根据最终的样式来渲染DOM树,这种做法性能方面确实会比较好一点。
**四:CSS是否会阻塞后续JS语句的执行?
会影响到js脚本的执行。因为js脚本不仅可以读取修改到dom,也可以读取修改到cssom。故在js脚本执行前,browser必须保证到css文件完全加载并解析完成,即cssom树完全构建好。这就导致了js执行的延迟,也因此导致html解析和渲染延迟。
(这就是css阻塞js执行,阻塞渲染的根本原因)
五:一些解决方法
1、在引入顺序上,css资源的引入要优于js脚本的引入
2、对css进行精简并尽快提供
3、可以用媒体类型(会加载不会阻塞)
4、用媒体查询(会记载,只有在符合的设备上才会进行阻塞)
<link href="style.css" rel="stylesheet">
<link href="style.css" rel="stylesheet" media="all">
<link href="portrait.css" rel="stylesheet" media="orientation:portrait">
<link href="print.css" rel="stylesheet" media="print">
第一个声明阻塞渲染,适用于所有情况。
第二个声明同样阻塞渲染:“all”是默认类型,如果您不指定任何类型,则隐式设置为“all”。因此,第一个声明和第二个声明实际上是等效的。
第三个声明具有动态媒体查询,将在网页加载时计算。根据网页加载时设备的方向,portrait.css 可能阻塞渲染,也可能不阻塞渲染。
最后一个声明只在打印网页时应用,因此网页首次在浏览器中加载时,它不会阻塞渲染。
最后,请注意“阻塞渲染”仅是指浏览器是否需要暂停网页的首次渲染,直至该资源准备就绪。无论哪一种情况,浏览器仍会下载 CSS 资源,只不过不阻塞渲染的资源优先级较低罢了。,然而这些等待的时间是完全不必要的。
注意:
与 同时在头部的话, 在上可能会更好。因为link在上的话,浏览器会先加载css,而后面body里的内容会被前面的js阻塞,原本body中的图片是可以和css并行加载的,现在只能等css执行完,js执行完,在执行(不太确定)。不过只是可能,是因为如果 的内容下载更快的话,是没影响的,但反过来的话, JS 就要等待了
六:js加载是否影响DOM的解析和渲染、js执行、css加载?(全部都影响)
- 通俗的原理:浏览器并不知道脚本的内容是什么,如果先行解析下面的DOM,万一脚本内全删了后面的DOM,浏览器就白干活了。更别谈丧心病狂的document.write。浏览器无法预估里面的内容,那就干脆全部停住,等脚本执行完再干活就好了。
JS的阻塞
1、所有浏览器在下载JS的时候,会阻止其他的一切活动(比如其他资源的下载,内容的呈现等等)。为了提高用户体验,新一代浏览器都支持并行下载JS,但是JS下载还是会阻止其他资源的加载(图片、css文件等等)
2、原因:浏览器为了防止出现JS修改DOM树,需要重构DOM树的情况,就会阻止其他资源的下载和呈现
3、嵌入JS会阻止所有内容的呈现,但是外部JSD只会阻止其后内容的显示
(因为嵌入js是不需要加载直接可以执行的)
4.浏览器遇到 <script>
标签时,会触发页面渲染,这也就解释了上文中为什么js要等到css加载完。因为浏览器不知道脚本里面是什么,所以在脚本之前会先渲染一次页面,(cssom和dom tree合成render tree),确保脚本能获取到最新的dom信息,尽管可能js并不需要。
七:对于js阻塞,有两种解决方法
defer(延迟执行)和async(异步执行)。这两种方法只适合与引入式的js脚本,不适合inline-script。
defer属性()
(这是延迟执行引入的js脚本(即脚本加载是不会导致解析停止,等到document全部解析完毕后,defer-script也加载完毕后,在执行所有的defer-script加载的js代码,再触发Domcontentloaded)
async属性()
(1)这是异步执行引入的js脚本文件
(2)与defer的区别是async会在加载完成后就执行,但是不会影响阻塞到解析和渲染。但是还是会阻塞load事件,所以async-script会可能在DOMcontentloaded触发前或后执行,但是一定会在load事件前触发。
引用(抄袭)的内容:
————————————————
版权声明:本文为CSDN博主「lulucong6」的原创文章,遵循CC 4.0 by-sa版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/lucaslow/article/details/78307396
作者:陈纪庚
链接:https://juejin.im/post/5b88ddca6fb9a019c7717096
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
原文链接:https://blog.csdn.net/a409051987/article/details/72231008