zoukankan      html  css  js  c++  java
  • 一次性分清DOMContentLoaded、window.onload、style

    简单来说

    1. onload事件触发时,页面上所有的DOM,样式表,图片,js等都完全加载完成;
    2. DOMContentLoaded事件触发时,仅仅是DOM加载完成,但不包括样式表,图片等;
    3. 先触发DOMContentLoaded事件,后触发load事件;

    看个栗子:

    <html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <title></title>
        <script type="text/javascript" src="script.js"></script>
        
        <script language="javascript">
            window.onload = haha;
            function haha(){console.log(document.getElementById("div1"));}
    
            if(document.addEventListener){
                function DOMContentLoaded(){
                    console.log("DOMContentLoaded");
                }
                document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false );
            }
        </script>
        
    </head>
    <body>
        <div id="div1">a</div>
    </body>
    </html>
    

    如上代码,我们分别绑定了onload和DOMContentLoaded两个事件,执行结果是先打印出DOMContentLoaded,再输出div1这个节点内容,佐证了以上三点。

    为什么会有两种事件?

    我们需要给一些元素的事件绑定事件处理函数,但潜在的问题是,如果那个元素还没有加载到页面上,但是绑定事件已经执行完了,是没有效果的;

    上述这两个事件就是用来避免这种情况的发生,将绑定函数放在两个事件中,保证能在页面的某些元素加载完毕之后再执行事件处理函数。

    当然DOMContentLoaded机制更加合理,因为我们可以容忍图片,flash延迟加载,却不可以容忍看见内容后页面不可交互。

    Jquery中的ready

    jq中,我们常常看到以下两种等价的写法

    $(document).ready(function(){
      // 在这里写你的代码...
    });
    
    $(function($) {    // 简化写法
      // 你可以在这里继续使用$作为别名...
    });
    

    在没有出现DOMContentLoaded事件出现以前,jq中的上述写法就是模拟这个事件的方法;

    window.onload

    window.onload无法注册多个事件处理函数,如下代码无法执行,会出现报错

    window.onload = function(){
      alert("test1");
    };
    
    window.onload = function(){
      alert("test2");
    };
    

    但是jq的$(document).ready()能同时编写多个,并且都会输出

    $(document).ready(function(){ 
       alert("Hello World"); 
    }); 
    $(document).ready(function(){ 
       alert("Hello again"); 
    }); 
    

    样式阻塞

    根据文档,该事件仅当在DOM加载完成之后触发,实际上有时并非如此!

    一般来说,外部样式文件并不会响到DOMCotentLoaded事件,它并不会等待外部样式文件加载完成。

    但是!!!在某些版本的Gecko和Webkit引擎的浏览器中,有些情况会使等待样式表加载完成后才触发DOMContentLoaded事件。最普遍的情况便是将脚本写在样式表后面:

    html

    <!DOCTYPE html>
    <head>
        <linkrel="stylesheet"href="stylesheet.css">
        <scriptsrc="script.js"></script>
    </head>
    <body>
        <divid="element">The element</div><
    /body>
    

    css

    #element { color: red; }
    

    js

    document.addEventListener('DOMContentLoaded',function(){
         alert(getComputedStyle(document.getElementById('element'),null).color);},
    false);
    

    如上,脚本是可以读出color属性值的,也就是说触发DOMContentLoaded事件时,样式表也加载完成了,样式表阻塞了DOM的构建!!!

    原因是浏览器猜测脚本可能会读取一些样式信息,如位置、颜色,显然脚本就需要等到样式的加载完成了。

    这也是为什么我们最好把脚本文件放到HTML文档的最后再加载,而不要把脚本放在head标签里,除非你清楚放在head标签里是必要的。

    异步脚本

    load与DOMContentLoaded标志着页面上两个重要的时刻:

    • DOMContentLoaded:DOM已经完成加载,此时可以为这些DOM元素绑定事件,初始化接口等
    • Load:其他外部资源均已加载完成,可以正确读出这些资源的信息,如图片的宽高等

    异步的script

    当解析器遇到内联标签的脚本<script>...</script>时,会阻塞DOM的构建,读取后会立即执行脚本。原因是可能这些脚本会影响DOM,因此需要等到这些脚本都执行完成了,才会触发DOMContentLoaded事件。

    阻塞同样对外联脚本有效(<script src="...">...</script>),浏览器需要等到加载后再执行完成才可以继续执行。

    对于外联的脚本,我们有方法让其延后执行,asyncdefer属性登场,他们可以让外部脚本延后执行,而不阻塞浏览器解析文档,但他们对内联脚本无效。

    async & defer 均可以让浏览器继续完成dom的加载,而不用等待脚本加载完成,他们的区别如下:

    区别 async defer
    执行顺序 谁先完成下载谁先执行 执行顺序始终遵循加载的顺序,即使先下载完成了
    DOMContentLoaded 如果页面加载时间较长,脚本可能会先执行;绝大多数会在DOMContentLoaded之后执行,但一定是在Load事件之前执行 脚本会在DOMContentLoaded之前执行,但不阻塞浏览器加载和解析文档,即defer脚本与浏览器加载顺序无关先后

    pic

    参考列表

    1. 从onload和DOMContentLoaded谈起
    2. https://juejin.im/post/5a36499551882529c70f34b5
  • 相关阅读:
    最难的事
    性格决定命运,习惯决定未来
    系统构架师之路
    时间是经不起浪费的
    如何投资自己,增加自身价值!
    最好的程序员大多是自学成才的
    杂记
    Win7启动Oracle出错
    推荐代码生成器工具排行
    Hibernate 与 Oracle 11g 的问题
  • 原文地址:https://www.cnblogs.com/CharmanderS5/p/9057468.html
Copyright © 2011-2022 走看看