• 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 world</p>
    </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">world</p>
        <script>
            console.log(document.getElementById('box1'));
            console.log(document.getElementById('box2'));
        </script>
        <p id="box2">hello</p>
    </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 解析

    这张图可以说是非常清晰了,结论:

    没有 defer 或 async,浏览器会立即加载并执行脚本,并且会阻塞DOM的解析
    有 async,浏览器立即加载脚本,加载的时候不会阻塞DOM解析,加载完了会立即执行,js执行时会阻塞DOM解析。如果有两个async的标签,两者的执行顺序也无法预料,是谁先加载完就谁先执行,这一点很不可控
    有 defer,浏览器立即加载脚本,加载的时候不会阻塞DOM解析,但是 js执行要在DOM解析完成之后,DOMContentLoaded 事件触发之前。如果有两个defer的标签,两者的执行顺序是按照加载顺序来的,谁先加载谁先执行
    ————————————————
    版权声明:本文为CSDN博主「Kobe_G」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/Kobe_G/article/details/124500818

  • 相关阅读:
    Java 动态代理 两种实现方法
    aspectj ----- 简介
    url中传递中文参数时的转码与解码
    JDK各个版本比较 JDK5~JDK10
    单例开始究竟能问多深及终极解决方案
    Map、Set、List 集合 差别 联系
    HashMap、LinkedHashMap、ConcurrentHashMap、ArrayList、LinkedList 底层实现
    springMVC :interceptors
    Shiro在Spring session管理
    SpringMVC Shiro与filterChainDefinitions
  • 原文地址:https://www.cnblogs.com/sexintercourse/p/16839521.html
Copyright © 2020-2023  润新知