zoukankan      html  css  js  c++  java
  • 解释css和js是如何阻塞浏览器渲染DOM的,并提出一些优化的方案

    浏览器是解析DOM生成DOM Tree,结合CSS生成的CSS Tree,最终组成render tree,再渲染页面。

    1.CSS不会堵塞DOM解析(DOM Tree的生成)

    <!DOCTYPE html>
       <html lang="en">
       <head>
      <meta charset="UTF-8">
      <title>Title</title>
      <link rel="stylesheet" href="/css/sleep3000-common.css">
      <script defer src="/js/logDiv.js">
       </head>
       <body>
      <div></div>
       </body>
    </html>

    #1.sleep3000-common.css 会延迟3秒钟返回,样式就是设置div块为浅蓝色
    #2.logDiv.js 代码如下,script标签加defer的含义是该脚本将在文档完成解析后,触发 DOMContentLoaded 事件前执行
    const div = document.querySelector('div');
    console.log(div);
    #3.执行结果
    先打印出div这个DOM节点,过3s左右之后才渲染出一个浅蓝色的div。
    这就证明了CSS 是不会阻塞 DOM 的解析的,尽管CSS下载需要3s,但这个过程中,浏览器不会傻等着CSS下载完,而是会解析DOM的。          

    2.CSS会堵塞页面的渲染

    <!DOCTYPE html>
       <html lang="en">
       <head>
      <meta charset="UTF-8">
      <title>Title</title>
           <style>
      div {
      100px;
      height: 100px;
      background: lightgreen;
      }
      </style>
      <link rel="stylesheet" href="/css/sleep3000-common.css">
       </head>
       <body>
      <div></div>
       </body>
    </html>

    #1.sleep3000-common.css 会延迟3ms返回,样式就是设置div块为浅蓝色
    #2.最终结果是浏览器会转圈圈三秒,之后呈现出一个浅蓝色的div,所以结果是CSS会堵塞页面的渲染。

    3.JS会堵塞DOM解析

    <!DOCTYPE html>
       <html lang="en">
       <head>
      <meta charset="UTF-8">
      <title>Title</title>
      <script src="/js/blok.js">
       </head>
       <body>
      <div></div>
       </body>
    </html>

    #1.block.js代码如下
    const arr = [];
    for (let i = 0; i < 10000000; i++) {
     arr.push(i);
     arr.splice(i % 3, i % 7, i % 5);
    }
    const div = document.querySelector('div');
    #2.最终结果浏览器转圈圈一会,这过程中不会有任何东西出现,之后打印出null。说明JS堵塞了DOM解析。
    #3.如果JS文件体积太大,同时你确定没必要阻塞DOM解析的话,不妨按需要加上defer或者async属性,此时脚本下载的过程中是不会阻塞DOM解析的。

    4.浏览器遇到 <script>且没有deferasync属性的标签时,会触发页面渲染。如果<script>标签前面有CSS资源,会等到CSS资源加载完毕之后再执行<script>脚本

    <!DOCTYPE html>
    <html lang="en">
       <head>
           <meta charset="UTF-8">
           <title>Title</title>
           <link rel="stylesheet" href="/css/sleep3000-common.css">
        </head>

         <body>
               <div></div>
               <script src="/js/logDiv.js">
               <style>
                   div {
                       background: lightgrey;
                  }
               </style>
               <script src="/js/sleep5000-logDiv.js"></script>
               <link rel="stylesheet" href="/css/common.css">
               </body>
    </html>

    #答案是等待3秒浅蓝色打印div,等待5秒浅灰色打印div,最后浅蓝色。由此可见,每次碰到<script>标签时,浏览器都会渲染一次页面。这是基于同样的理由,浏览器不知道脚本的内容,因而碰到脚本时,只好先渲染页面,确保脚本能获取到最新的DOM元素信息,尽管脚本可能不需要这些信息。

    5.优化方案:

    <script>最好放底部,<link>最好放头部,如果头部同时有<script><link>的情况下,最好将<script>放在<link>上面

    6.附:defer 与 async

    如果我们不想<script>堵塞页面的解析,我们可以给<script>标签添加defer或者async属性。defer和async的区别主要如下:

    1.执行时机不同:
    defer的脚本将在DOM解析完成后、触发 DOMContentLoaded 事件前执行
    async的脚本一旦加载完毕,就会执行(不论是在DOM解析阶段还是DOMContentLoaded之前之后,但是一定是在window.load之前执行)
    2.执行顺序不同:
    defer能保证多个脚本按照书写顺序执行
    async不能保证多个脚本的执行顺序

     

  • 相关阅读:
    综合练习:词频统计
    Dart SDK 2.0安装问题
    The DartEditor executable launcher was unable to locate its companion shared library.
    pycharm中如何正确配置pyqt5
    发现黑苹果带双显示器无法启动的原因
    Pycharm中用鼠标改变字体大小
    失望的visual studio for mac
    laravel 函数测试 --- Route::has()
    laragon 之Nginx
    laragon 之xdebug
  • 原文地址:https://www.cnblogs.com/lishuge/p/12323868.html
Copyright © 2011-2022 走看看