css、js的加载是否阻塞DOM的解析与渲染

首先说一下浏览器渲染页面的流程:
浏览器内核(渲染进程)拿到静态资源后,渲染大概可以划分成以下几个步骤:

  • 解析html构建dom树
  • 解析css构建render树(将CSS代码解析成树形的数据结构,然后结合DOM合并成render树)
  • 布局render树(Layout/reflow),负责各元素尺寸、位置的计算
  • 绘制render树(paint),绘制页面像素信息
  • 浏览器会将各层的信息发送给GPU,GPU会将各层合成(composite),显示在屏幕上。

从以上步骤可以得出几个结论:
1.html和css的加载和解析是异步的,不会互相干扰
2.只有等dom树和cssom树构建完成并且合并成render树之后,页面才开始渲染,所以css的加载不会影响dom的解析,但会影响dom的渲染

根据以上的基本结论,我们开始探索js加载和html、css的关系:

一、JS 会阻塞 DOM 解析

当解析器遇到script标签时(不带有async/defer属性),浏览器会停止DOM的解析,会一直等到该script的加载并执行后,才继续往下解析。比较合理的解释就是,首先浏览器无法知晓JS的具体内容,倘若先解析DOM,万一JS内部全部删除掉DOM,那么浏览器就白忙活了,所以就干脆暂停解析DOM,等到JS执行完成再继续解析。

二、CSS 会阻塞 JS 的执行

css的加载会阻塞js的执行,这一点不是很好理解,看以下代码:

<head>
  <link rel="stylesheet" href="./style.css?sleep=3000"> //假设css的加载会花3s
  <script src="./index.js">script>
head>
<body>
  <p>hello worldp>
body>

我们从head开始解析,首先遇到link标签,去加载css(加载需要3s),此时浏览器不会停下来,会继续往下解析,然后遇到script标签,开始加载js,js很快就加载完了,但是js不会马上执行,因为它会等到上面的css资源加载完成之后再开始执行。从而导致了下面的p标签一直没有得到解析,因为上面说了js是会阻塞DOM的解析的,浏览器会等到js执行了才会继续往下解析DOM。

千万不要认为是css的加载阻塞了DOM的解析!

流程是:css和js可以同时去加载—>css加载很慢,即使js已经加载完了也会等到css加载完了才开始执行—>js一直不执行所以阻塞了DOM的解析

那么为什么js明明都加载完了,还要等css加载完才开始执行呢?

可以这样理解,浏览器并不知道js中的代码会干些什么,js可以去改动DOM,也可以获取/改变css样式。js要获取正确的样式就必须等css加载完

三、js会触发页面的渲染

大概意思是,浏览器在解析时,如果遇到了script标签,会先渲染一次这个script标签之前的DOM,然后再去加载和执行js。因为js是可以操作DOM的,如果浏览器不先去渲染一次,js获取的DOM就会是null。比如:

<body>
    <p id="box1">worldp>
    <script>
        console.log(document.getElementById('box1'));
        console.log(document.getElementById('box2'));
    script>
    <p id="box2">hellop>
body>

上面代码的js是可以获取到id为box1的p标签,但是不能获取box2的p标签,原因很简单,因为script在box2前面。js执行的时候,box2还没有被解析和渲染。

另外说一下,浏览器解析DOM时,虽然会一行一行向下解析,但是它会预先加载具有引用标记的外部资源(例如带有src标记的script、link标签),而在解析到此标签时,则无需再去加载,直接运行,以此提高运行效率。

以上参考:https://juejin.cn/post/6973949865130885157

四:关于script的async/defer属性

关于两者的区别,先直接上图:

蓝色线代表网络读取(加载),红色线代表js执行,这俩都是针对脚本的;绿色线代表 HTML 解析
css、js的加载是否阻塞DOM的解析与渲染_第1张图片
这张图可以说是非常清晰了,结论:

  • 没有 defer 或 async,浏览器会立即加载并执行脚本,并且会阻塞DOM的解析
  • 有 async,浏览器立即加载脚本,加载的时候不会阻塞DOM解析,加载完了会立即执行,js执行时会阻塞DOM解析。如果有两个async的标签,两者的执行顺序也无法预料,是谁先加载完就谁先执行,这一点很不可控
  • 有 defer,浏览器立即加载脚本,加载的时候不会阻塞DOM解析,但是 js执行要在DOM解析完成之后,DOMContentLoaded 事件触发之前。如果有两个defer的标签,两者的执行顺序是按照加载顺序来的,谁先加载谁先执行

你可能感兴趣的:(JS,CSS,HTML,css,javascript,前端)