DOMContentLoaded时间触发与js,css,img的关联

DOMContentLoaded触发原理:

1、规范总是那么的晦涩,但至少有一点是可以明确了的,就是在JS(不包括动态插入的JS)执行完之后,才会触发DOMContentLoaded事件。

2、DOMContentLoaded事件本身不会等待CSS文件、图片、iframe加载完成。
它的触发时机是:加载完页面,解析完所有标签(不包括执行CSS和JS),并如规范中所说的设置interactive 和执行每个静态的script标签中的JS,然后触发。
而JS的执行,需要等待位于它前面的CSS加载(如果是外联的话)、执行完成,因为JS可能会依赖位于它前面的CSS计算出来的样式

实践是检验真理的唯一标准

实践是检验真理的唯一标准

实验1:DOMContentLoaded事件不直接等待CSS文件、图片的加载完成

index.html:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title></title>
    <link rel="stylesheet" type="text/css" href="./css/main.css">
</head>
<body>
    <p>Content</p>
    <img src="./img/chrome-girl.jpg">
</body>
</html>


图一

如果页面中没有script标签,DOMContentLoaded事件并没有等待CSS文件、图片加载完成。

Chrome开发者工具的Timeline面板可以帮我们记录下浏览器的一举一动。图一中红色小方框中的蓝线,表示DOMContentLoaded事件,它右边的红线和绿线分别表示load事件和First paint,鼠标hover在这些线露出灰色方框下面的一小部分时就会出现带有说明文字的tips(这交互够反人类的对吧!)。

实验2:DOMContentLoaded事件需要等待JS执行完才触发

index.html:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title></title>
    <script type="text/javascript">
        console.timeStamp(‘Inline script before link in head‘);
        window.addEventListener(‘DOMContentLoaded‘, function(){
            console.timeStamp(‘DOMContentLoaded event‘);
        });
    </script>
    <link rel="stylesheet" type="text/css" href="./css/main.css">
    <script type="text/javascript">
        console.timeStamp(‘Inline script after link in head‘);
    </script>
</head>
<body>
    <p>Content</p>
    <img src="./img/chrome-girl.jpg">
    <script type="text/javascript" src="./js/main.js"></script>
</body>
</html>

main.js:

console.timeStamp(‘External script after link in body‘);

图二

如果页面中静态的写有script标签,DOMContentLoaded事件需要等待JS执行完才触发。
而script标签中的JS需要等待位于其前面的CSS的加载完成。

console.timeStamp() 可以向Timeline中添加一条记录,并对应上方的一条黄线。

从图二中可以看出,在CSS之前的JS立刻得到了执行,而在CSS之后的JS,需要等待CSS加载完后才执行,比较明显的是main.js早就加载完了,但还是要等main.css加载完才能执行。而DOMContentLoaded事件,则是在JS执行完后才触发。滑动Timeline面板中表示展示区域的滑块,如图三,放大后即可看到表示DOMContentLoaded事件的蓝线(之前跟黄线和绿线靠的太近了),当然,通过 console.timeStamp()向TimeLine中添加的记录也可证明其触发时间。


图三

现代浏览器会并发的预加载CSS, JS,也就是一开始就并发的请求这些资源,但是,执行CSS和JS的顺序还是按原来的依赖顺序(JS的执行要等待位于其前面的CSS和JS加载、执行完)。先加载完成的资源,如果其依赖还没加载、执行完,就只能等着。

实验3:img何时开始解码、绘制?

从图三中我们可以发现一个有趣的地方:img的请求老早就发出了,但延迟了一段时间才开始解码。如图二、图三中的红框所示,截图中只框出了一部分表示解码的记录,而实际上这些表示解码的记录一直持续到img加载结束,如图四所示,img是一边加载一边解码的:


图四

抱着“猜想——验证”的想法,我猜想这是因为img这个资源是否需要展现出来,需要等 所有的JS和CSS的执行完 才知道,因为main.js可能会执行某些DOM操作,比如删除这个img元素,或者修改其src属性,而CSS可能会将其 display: none 。


图五


图六


图七

图五中没有JS和CSS,img的数据一接收到就马上开始解码了。
图六中没有JS,但img要等到CSS加载完才开始解码。
图七的代码跟图六的代码唯一的区别是CSS把img给 display: none; ,这使得img虽然请求了,但根本没有进行解码。
这说明,img是否需要解码、绘图(paint)出来,确实需要等CSS加载、执行完才能知道。也就是说,CSS会阻塞img的展现!那么JS呢?


图八

图八对应的代码:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title></title>
    <script type="text/javascript">
        console.timeStamp(‘Inline script in head‘);
        window.addEventListener(‘DOMContentLoaded‘, function(){
            console.timeStamp(‘DOMContentLoaded event‘);
        });
    </script>
</head>
<body>
    <p>Content</p>
    <img src="./img/chrome-girl.jpg">
    <script type="text/javascript" src="./js/main.js"></script>
</body>
</html>

非常令人惊讶,在有JS而没有CSS的页面中,img居然能够在收到数据后就立刻开始解码、绘图(paint),也就是说,JS并没有阻塞img的展现!这跟我们以前理解的JS会阻塞img资源的传统观念不太一样,看来Chrome对img的加载和展现做了新的优化。



我们常用的jQuery的 $(document).ready() 方法,就是对DOMContentLoaded事件的监听(当然,其内部还会通过模拟DOMContentLoaded事件和监听onload事件来提供降级方案)。通常推荐在DOMContentLoaded事件触发的时候为DOM元素注册事件。所以尽快的让DOMContentLoaded事件触发,就意味着能够尽快让页面可交互:

  1. 减小CSS文件体积,把单个CSS文件分成几个文件以并行加载,减少CSS对JS的阻塞时间
  2. 次要的JS文件,通过动态插入script标签来加载(动态插入的script标签不阻塞DOMContentLoaded事件的触发)
  3. CSS中使用的精灵图,可以利用对img的预加载,放在html中跟CSS文件一起加载

在做实验的过程中,感觉Chrome开发者工具的Timeline面板非常强大,浏览器的一举一动都记录下来。以前我们前端开发要想理解、探索浏览器的内部行为,或者摸着石头过河的做黑盒测试,或者事倍功半的研究浏览器源码,唯一高效点的做法就是学习别人的研究经验,看老外的文章,但浏览器的发展日新月异(比如这次实验发现的JS不阻塞img的展现),别人的经验始终不是最新、最适合的,关键是要结合自己的业务、需求场景,有针对性的做分析和优化。

转发地址:http://www.alloyteam.com/2014/03/effect-js-css-and-img-event-of-domcontentloaded/

时间: 2024-10-24 22:52:00

DOMContentLoaded时间触发与js,css,img的关联的相关文章

JS/CSS/IMG加载顺序关系之DOMContentLoaded事件

DOMContentLoaded介绍 DOMContentLoaded事件的触发条件是: 将会在"所有的DOM全部加载完毕并且JS加载执行后触发". 但如果"js是通过动态加载进来的话,是不会影响到DOMContentLoaded的触发时间" 如下图所示,蓝色的线代表DOMContentLoaded开始触发,但前提是JS已经加载完毕并执行了. (仅仅是DOM 并不是onload事件整个页面全部加载完毕触发,DOMContentLoaded比onload要早触发 请区

js css样式操作代码(批量操作)

js css样式操作代码(批量操作) 作者: 字体:[增加 减小] 类型:转载 时间:2009-10-09 用js控制css样式,能让网页达到良好的的用户体验甚至是动画的效果.并且考虑到效率. 我们用js书写css样式通常会用下面的两种方式: 一般情况下我们用js设置元素对象的样式会使用这样的形式: 复制代码 代码如下: var element= document.getElementById(”id”); element.style.width=”20px”; element.style.he

Web性能优化之动态合并JS/CSS文件并缓存客户端

在Web开发过程中,会产生很多的js/css文件,传统的引用外部文件的方式会产生多次的http请求,从而加重服务器负担且网页加载缓慢,如何在一次请求中将多个文件一次加载出来?接下来给大家介绍在ASP.NET中动态合并加载多个js或css文件.原理:减少请求服务器的次数达到优化效果先给大家看一下传统引用方式和优化后的比较:1.传统引用方式(下图): 这样的引用方式将会请求5个js文件也就是5次http请求(下图): 2.我们来看看优化后(下图): 大家可以看到修改后只有一次请求,花费的时间节省了很

动态加载js css 插件

简介 动态加载js,css在现在以及将来肯定是很重要的.目前来看前端代码编写的业务量已经远远超过后端编写的.随着对用户体验度逐渐增强,前端业务复杂,加载速度变得很慢很慢.为了解决这个问题,目前出现的两个前端模块加载器为require.js与sea.js,这两款模块加载器都不错.但是呢,有时候我仅仅需要的只是动态加载一个js,不需要把代码模块化,那我们只能自己手写一个加载函数. 简单的加载js /** * HTML动态加载js * @path {String} src地址必须带有后缀名.js *

让eclipse完全支持HTML/JS/CSS智能提示

平时用eclipse开发jsp页面时智能提示效果不太理想,通过修改eclipse配置让其完全智能提示HTML/JS/CSS代码,具体步骤如下 1.打开eclipse→Windows→Preferences→Java→Editor→Content Assist 修改Auto Activation triggers for java的值为:".abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVW"(惯例""要去掉)   点击

JS/CSS缓存杀手——VS插件

背景 前些天去考科目二,感觉经历了一场不是高考却胜似高考的考试(10年前的5分之差, 还是难以释怀)!    一行八人,就我学的时间最少(4天,8人一辆车),教练都觉得我肯定还得再来一次! 靠着运气和信念,惊险的通过了侧方停车和倒车入库,终于还是抚慰了一下10年前那颗年轻的心!  ----------感慨完毕,回归主题---------- 终于修改完了客户提交的bugs,发布.更新.测试.邮件通知,悠哉悠哉的浏览博客园...然后客户来了... 客户:我提的需求怎么都没修改,这个按钮颜色也没变,点

JS+CSS打造仿QQ面板的三级折叠下拉菜单

<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>JS+CSS打造仿QQ面板的三级折叠下拉菜单-石家庄地毯</title> <style type="text/css"> *{ margin:0px; padding:0px; border:0p

JavaScript之打飞机小游戏 js css

先引入    jquery-1.12.4.min.js 和    lodash.min.js css .container{ width: 320px; height: 568px; margin: 0 auto; text-align: center; position: relative; overflow: hidden; } .start-page{ width: 320px; height: 568px; background: url('../images/start_bg.png'

HTML+JS+CSS 实现下拉菜单

最近在看视频学习做一些HTML+JS+CSS的实例,第一个是实现下拉菜单. 5.7 制作的思路是:1.静态网页的制作 2.动态特效实现菜单的显示和隐藏(三种方法:css.JavaScript.jQuery) 3.浏览器的兼容问题(低版本IE可能不支持等) 在用css实现时,由于盒子模型有自己默认的margin和padding值,所以要reset. 有一点比较有疑问的实,老师在视频里说position:absolute要和left.top同时使用.这是为什么?在实现的时候,我并没有使用left和t