zoukankan      html  css  js  c++  java
  • js和css的加载造成阻塞

    浏览器渲染原理图:

     

    bar.js

    var count_bar = 0;
    var start_bar = new Date();
    for(var i=0;i<100000;i++){
      for(var j=0;j<10000;j++){
        count_bar++;
      }
    }
    var end_bar = new Date();
    console.log(end_bar -  start_bar,'bar');

     foo.js

    var count_foo = 0;
    var start_foo = new Date();
    for(var i=0;i<100000;i++){
      for(var j=0;j<10000;j++){
        count_foo++;
      }
    }
    var end_foo = new Date();
    console.log(end_foo - start_foo,'foo');

     ress.js

    var count_ress = 0;
    var start_ress = new Date();
    for(var i=0;i<100000;i++){
      for(var j=0;j<10000;j++){
        count_ress++;
      }
    }
    var end_ress = new Date();
    console.log(end_ress - start_ress,'ress');

     demo.html

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>Document</title>
        <script src="js/bar.js"></script>
        <script src="js/foo.js"></script>
        <script src="js/ress.js"></script>
    </head>
    
    <body>
        <div id="dd">
            div 1
        </div>
        <p>paragraph</p>
    
        <div>
            div 2
        </div>
    </body>
    
    </html>

     来自于safari的截图

    1.现代浏览器会并行加载js文件,参见截图的start time列,但是按照书写顺序执行代码

    2.加载或者执行js时会阻塞对标签的解析,也就是阻塞了dom树的形成,只有等到js执行完毕,浏览器才会继续解析标签。没有dom树,浏览器就无法渲染,所以当加载很大的js文件时,可以看到页面很长时间是一片空白

    之所以会阻塞对标签的解析是因为加载的js中可能会创建,删除节点等,这些操作会对dom树产生影响,如果不阻塞,等浏览器解析完标签生成dom树后,js修改了某些节点,那么浏览器又得重新解析,然后生成dom树,性能比较差

    修改html,添加事件监听

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>Document</title>
        <script src="js/bar.js"></script>
        <script src="js/foo.js"></script>
        <script src="js/ress.js"></script>
    </head>
    <body>
        <div id="dd">
            div 1
        </div>
        <p>paragraph</p>
    
        <div>
            div 2
        </div>
        <img src="images/beauty.png" alt="" onload="console.log('image loaded')">
        
        <script>
            document.addEventListener("DOMContentLoaded",function(){
                console.log("dom content loaded");
            })
            window.onload = function(){
                console.log('resources loaded');
            }
        </script>
    </body>
    
    </html>

     来自chrome的截图

    1.文档解析完成时触发domcontentloaded事件。浏览器逐行解析,遇到</html>表示解析完成

    2.当所有的资源都加载完后触发window的load事件。

    3.监听资源加载完成有四种方式

      3.1 window.onload = function(){....}

      3.2 window.addEventListener("load",function(){....});

      3.3 document.body.onload = function(){....}

      3.4 <body onload = "....">

    错误方式: document.body.addEventListener('load',function(){....});

    这块各浏览器表现没有统一标准,推荐使用window.onload来监听,比较保险

    给script标签添加defer属性,仅限外部脚本

    <script src="js/bar.js" defer></script>

     结果:

    1.defer属性表示延迟脚本的执行,等到整个文档解析完再执行

    2.defer属性能延迟执行,但是不会延迟下载,浏览器遇到script就立即下载脚本

    3.文档解析完成时,脚本被执行,此时也会触发domcontentloaded事件,优先执行脚本

    4.多个标签添加defer属性,执行顺序仍然是按书写顺序

    给script标签添加async属性,仅限外部脚本

    <script src="js/bar.js" async></script>
    <script src="js/foo.js" async></script>
    <script src="js/ress.js" async></script>

     结果

    chrome:

     safari:

    firefox:

    1.async属性的作用是让浏览器异步加载脚本文件。在加载脚本文件的时候,浏览器能继续标签的解析。

    2.异步脚本一定会在load事件之前执行,但可能会在domcontentloaded事件之前或者之后执行。

    3.异步脚本之间的执行顺序不确定,可能不会按照书写顺序执行

    删除script外部链接

    demo.html

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>Document</title>
    </head>
    
    <body>
        <div>
            before
        </div>
        <script>
            var count = 0;
            for (var i = 0; i < 100000; i++) {
                for (var j = 0; j < 10000; j++) {
                    count++;
                }
            }
            console.log(count);
        </script>
        <div id="dd">
            div 1
        </div>
        <p>paragraph</p>
    
        <div>
            div 2
        </div>
        <img src="images/beauty.png" alt="" onload="console.log('image loaded')">
    
        <script>
            document.addEventListener("DOMContentLoaded", function () {
                console.log("dom content loaded");
            })
            window.onload = function () {
                console.log('resources loaded');
            }
        </script>
    </body>
    
    </html>

     结果是:

    1.持续一段空白页面后,才有东西出来。也就是说页面元素的渲染是整体的。浏览器构建完整个DOM树后渲染,不会因为<div>before</div>出现在<script>....</script>之前,before就会先出现。

    2.通常把script内容放在body最后,这样脚本文件不会阻止其他资源的下载,但是由于DOM的解析完成是依据是否遇到</html>标签,那么浏览器当遇到script标签时会立即执行里面的代码,导致DOM的解析被阻塞。

     css对渲染的阻塞

    <html lang="en">
    
    <head>
        <title>css阻塞</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
       <script>
           console.log('before css');
           document.addEventListener("DOMContentLoaded",function(){
               console.log("content loaded");
               f();
           })
           function f(){
               console.log(document.querySelectorAll("h1"));
           }
       </script>
        <link href="https://cdn.bootcss.com/bootstrap/4.0.0-alpha.6/css/bootstrap.css" rel="stylesheet">
        <link href="http://netdna.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.css" rel="stylesheet">
        <link href="http://apps.bdimg.com/libs/bootstrap/2.3.2/css/bootstrap-responsive.css" rel="stylesheet">
    
        <script>
            console.log("after css");
        </script>
    </head>
    
    <body>
        <h1>这是红色的</h1>
        <h1>head</h1>
    
    </body>
    
    </html>

     safari截图:

     

     输出结果:

    1.css文件是并行下载的

    2.css的下载会阻塞后面js的执行,以上代码先执行"before css",然后开始下载三个css文件,文件下载完成,执行"after css"

    3.css的下载不会阻塞后面js的下载,但是js下载完成后,被阻塞执行

    将"after css"那段代码注释掉,发生了巨大的改变

    可以看到domcontentloaded事件触发了,但是此时页面是空白的

    这是因为虽然js会阻止dom的解析,但是css不会阻止dom的解析。

    第一个案例中,遇到"before css"代码,dom被阻塞,执行js代码,执行完之后继续解析,遇到link标签后,开始下载css文件,dom解析继续,遇到script标签,dom解析被阻塞,且js代码不会被执行,等到css文件下载并且解析完成后,js代码开始执行,执行完之后,继续dom解析,最后生成dom树,抛出domcontentloaded事件,然后浏览器开始渲染页面,出现页面元素。

    第二个案例中,没有"after css"代码,那么在下载css文件的时候,dom解析没有被阻塞,那么当设置下载网速20kb时,css还没下载解析完成,dom解析就已经完成了。此时抛出domcontentloaded事件,但是浏览器此时还不能渲染元素,因为元素的渲染除了dom树外还需要cssdom配合,确定元素的大小位置。这样就导致了css文件没有下载解析完成时,dom解析完成了,但是渲染被阻塞着。

  • 相关阅读:
    CVSps 3.8 发布,CVS 资料库更改收集
    Cobra WinLDTP 3.0 发布,GUI 自动化测试
    SolusOS 2 Alpha 6 发布,桌面 Linux 发行
    微软 Windows Phone 8 原创应用大赛起航
    JAVA削足适履适应RESTful设计
    如何撰写编程书籍
    Synbak 2.1 发布,系统备份工具
    LibreOffice 4.0 RC1 发布,支持火狐兼容主题
    Rails 3.2.11 发布,修复关键安全问题
    haveged 1.7 发布,随机数生成器
  • 原文地址:https://www.cnblogs.com/bibiafa/p/9364986.html
Copyright © 2011-2022 走看看