(1)在chrome浏览器的开发过程当中,咱们会看到network面板中有这两个数值,分别对应网 络请求上的标志线,这两个时间数值分别表明什么?javascript
(2)咱们一再强调将css放在头部,将js文件放在尾部,这样有利于优化页面的性能,为何这种方式可以优化性能?css
(3)在用jquery的时候,咱们通常都会将函数调用写在ready方法内,这是什么原理?html
首先看一下java
DOMContentLoaded顾名思义,就是dom内容加载完毕。那什么是dom内容加载完毕呢?咱们从打开一个网页提及。当输入一个URL,页面的展现首先是空白的,而后过一会,页面会展现出内容,可是页面的有些资源好比说图片资源还没法看到,此时页面是能够正常的交互,过一段时间后,图片才完成显示在页面。从页面空白到展现出页面内容,会触发DOMContentLoaded事件。而这段时间就是HTML文档被加载和解析完成。jquery
这时候问题又来了,什么是HTML文档被加载和解析完成。要解决这个问题,咱们就必须了解浏览器渲染原理。面试
当咱们在浏览器地址输入URL时,浏览器会发送请求到服务器,服务器将请求的HTML文档发送回浏览器,浏览器将文档下载下来后,便开始从上到下解析,解析完成以后,会生成DOM。若是页面中有css,会根据css的内容造成CSSOM,而后DOM和CSSOM会生成一个渲染树,最后浏览器会根据渲染树的内容计算出各个节点在页面中的确切大小和位置,并将其绘制在浏览器上。chrome
下面就是页面加载和解析过程当中,浏览器的一个快照浏览器
上面咱们看到在解析html的过程当中,html的解析会被中断,这是由于javascript会阻塞dom的解析。当解析过程当中遇到<script>标签的时候,便会中止解析过程,转而去处理脚本,若是脚本是内联的,浏览器会先去执行这段内联的脚本,若是是外链的,那么先会去加载脚本,而后执行。在处理完脚本以后,浏览器便继续解析HTML文档。安全
同时javascript的执行会受到标签前面样式文件的影响。若是在标签前面有样式文件,须要样式文件加载并解析完毕后才执行脚本。这是由于javascript能够查询对象的样式。服务器
这里须要注意一点,在如今浏览器中,为了减缓渲染被阻塞的状况,现代的浏览器都使用了猜想预加载。当解析被阻塞的时候,浏览器会有一个轻量级的HTML(或CSS)扫描器(scanner)继续在文档中扫描,查找那些未来可能可以用到的资源文件的url,在渲染器使用它们以前将其下载下来。
在这里咱们能够明确DOMContentLoaded所计算的时间,当文档中没有脚本时,浏览器解析完文档便能触发 DOMContentLoaded 事件;若是文档中包含脚本,则脚本会阻塞文档的解析,而脚本须要等位于脚本前面的css加载完才能执行。在任何状况下,DOMContentLoaded 的触发不须要等待图片等其余资源加载完成。
接下来,咱们来讲说load,页面上全部的资源(图片,音频,视频等)被加载之后才会触发load事件,简单来讲,页面的load事件会在DOMContentLoaded被触发以后才触发。
咱们在 jQuery 中常用的 $(document).ready(function() { // ...代码... }); 其实监听的就是 DOMContentLoaded 事件,而$(document).load(function() { // ...代码... }); 监听的是 load 事件。在用jquery的时候,咱们通常都会将函数调用写在ready方法内,就是页面被解析后,咱们就能够访问整个页面的全部dom元素,能够缩短页面的可交互时间,提升整个页面的体验。
下面咱们在来看看如何实现这两个函数
一、onload事件
onload事件全部的浏览器都支持,因此咱们不须要什么兼容,只要经过调用
window.onload = function(){ }
二、DOMContentLoaded 事件
DOMContentLoaded不一样的浏览器对其支持不一样,因此在实现的时候咱们须要作不一样浏览器的兼容。
1)支持DOMContentLoaded事件的,就使用DOMContentLoaded事件;
2)IE六、IE7不支持DOMContentLoaded,但它支持onreadystatechange事件,该事件的目的是提供与文档或元素的加载状态有关的信息。
3) 更低的ie还有个特有的方法doScroll, 经过间隔调用:document.documentElement.doScroll("left");
能够检测DOM是否加载完成。 当页面未加载完成时,该方法会报错,直到doScroll再也不报错时,就表明DOM加载完成了。该方法更接近DOMContentLoaded的实现。
function ready(fn){ if(document.addEventListener) { document.addEventListener('DOMContentLoaded', function() { document.removeEventListener('DOMContentLoaded',arguments.callee, false); fn(); }, false); } // 若是IE else if(document.attachEvent) { // 确保当页面是在iframe中加载时,事件依旧会被安全触发 document.attachEvent('onreadystatechange', function() { if(document.readyState == 'complete') { document.detachEvent('onreadystatechange', arguments.callee); fn(); } }); // 若是是IE且页面不在iframe中时,轮询调用doScroll 方法检测DOM是否加载完毕 if(document.documentElement.doScroll && typeof window.frameElement === "undefined") { try{ document.documentElement.doScroll('left'); } catch(error){ return setTimeout(arguments.callee, 20); }; fn(); } } };
最后咱们来回答这个问题:咱们为何一再强调将css放在头部,将js文件放在尾部
在面试的过程当中,常常会有人在回答页面的优化中提到将js放到body标签底部,缘由是由于浏览器生成Dom树的时候是一行一行读HTML代码的,script标签放在最后面就不会影响前面的页面的渲染。那么问题来了,既然Dom树彻底生成好后页面才能渲染出来,浏览器又必须读彻底部HTML才能生成完整的Dom树,script标签不放在body底部是否是也同样,由于dom树的生成须要整个文档解析完毕。
咱们再来看一下chrome在页面渲染过程当中的,绿色标志线是First Paint的时间。纳尼,为何会出现firstpaint,页面的paint不是在渲染树生成以后吗?其实现代浏览器为了更好的用户体验,渲染引擎将尝试尽快在屏幕上显示的内容。它不会等到全部HTML解析以前开始构建和布局渲染树。部分的内容将被解析并显示。也就是说浏览器可以渲染不完整的dom树和cssom,尽快的减小白屏的时间。假如咱们将js放在header,js将阻塞解析dom,dom的内容会影响到First Paint,致使First Paint延后。因此说咱们会将js放在后面,以减小First Paint的时间,可是不会减小DOMContentLoaded被触发的时间。