声明:此文章为转载(点击查看原文),如有侵权24小时内删除。联系QQ:1522025433.

(1)在chrome浏览器的开发过程中,我们会看到network面板中有这两个数值,分别对应网 络请求上的标志线,这两个时间数值分别代表什么?

(2)我们一再强调将css放在头部,将js文件放在尾部,这样有利于优化页面的性能,为什么这种方式能够优化性能?

(3)在用jquery的时候,我们一般都会将函数调用写在ready方法内,这是什么原理?

首先看一下

DOMContentLoaded顾名思义,就是dom内容加载完毕。那什么是dom内容加载完毕呢?我们从打开一个网页说起。当输入一个URL,页面的展示首先是空白的,然后过一会,页面会展示出内容,但是页面的有些资源比如说图片资源还无法看到,此时页面是可以正常的交互,过一段时间后,图片才完成显示在页面。从页面空白到展示出页面内容,会触发DOMContentLoaded事件。而这段时间就是HTML文档被加载和解析完成。

这时候问题又来了,什么是HTML文档被加载和解析完成。要解决这个问题,我们就必须了解浏览器渲染原理。

当我们在浏览器地址输入URL时,浏览器会发送请求到服务器,服务器将请求的HTML文档发送回浏览器,浏览器将文档下载下来后,便开始从上到下解析,解析完成之后,会生成DOM。如果页面中有css,会根据css的内容形成CSSOM,然后DOM和CSSOM会生成一个渲染树,最后浏览器会根据渲染树的内容计算出各个节点在页面中的确切大小和位置,并将其绘制在浏览器上。

下面就是页面加载和解析过程中,浏览器的一个快照

上面我们看到在解析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元素,可以缩短页面的可交互时间,提高整个页面的体验。

下面我们在来看看如何实现这两个函数

1、onload事件

onload事件所有的浏览器都支持,所以我们不需要什么兼容,只要通过调用

window.onload = function(){

}

2、DOMContentLoaded 事件

DOMContentLoaded不同的浏览器对其支持不同,所以在实现的时候我们需要做不同浏览器的兼容。

1)支持DOMContentLoaded事件的,就使用DOMContentLoaded事件;

2)IE6、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被触发的时间。

DOMContentLoaded与load的区别的更多相关文章

  1. 【转载】DOMContentLoaded与load的区别

    DOMContentLoaded与load的区别   (1)在chrome浏览器的开发过程中,我们会看到network面板中有这两个数值,分别对应网 络请求上的标志线,这两个时间数值分别代表什么? ( ...

  2. js DomContentLoaded 和 load 的区别

    如题:DOMContentLoaded和load都是页面加载的时候触发的事件.区别在于触发的时机不一样. 浏览器渲染页面DOM文档加载的步骤: 1.解析HTML结构. 2.加载外部脚本和css文件. ...

  3. js中DOMContentLoaded和load的区别

    如题:DOMContentLoaded和load都是页面加载的时候触发的事件.区别在于触发的时机不一样. 浏览器渲染页面DOM文档加载的步骤: 1.解析HTML结构. 2.加载外部脚本和css文件. ...

  4. 事件DOMContentLoaded和load的区别

    1.当 onload 事件触发时,页面上所有的DOM,样式表,脚本,图片,flash都已经加载完成了. 2.当 DOMContentLoaded 事件触发时,仅当DOM加载完成,不包括样式表,图片,f ...

  5. DOMContentLoaded 和 Load 事件 区别(待补充)

    javascript会阻塞dom的解析.当解析过程中遇到<script>标签的时候,便会停止解析过程,转而去处理脚本,如果脚本是内联的,浏览器会先去执行这段内联的脚本,如果是外链的,那么先 ...

  6. DOMContentLoaded和load的区别

    一.概念 DOMContentLoaded 当初始的 HTML 文档被完全加载和解析完成之后,DOMContentLoaded 事件被触发,而无需等待样式表.图像和子框架的完成加载. load loa ...

  7. ready与load的区别

    JQuery里有ready和load事件 $(document).ready(function() { // ...代码... }) //document ready 简写 $(function() ...

  8. Hibernate中session.get()和session.load()的区别

    -- 翻译自https://www.mkyong.com/hibernate/different-between-session-get-and-session-load/ 很多时候你会发现,使用Hi ...

  9. Get和Load的区别----hibernate

    Get和Load的区别

随机推荐

  1. js对象之window和document区别

    window是整个页面的全局环境,而document可以理解为整个页面这个最大的元素(整个dom树) window: 可以看到window下面有很多变量 document: 可见document是整个 ...

  2. RocketMQ在windows环境下的安装

    原博地址:https://www.jianshu.com/p/4a275e779afa 一.预备环境 1.系统 Windows 2. 环境 JDK1.8.Maven.Git 二. RocketMQ部署 ...

  3. IDEA中设置Tab多行显示、打开过多自动关闭的方法

    IDEA中默认Tab是单行显示的,而且默认允许同时打开10个Tab,继续打开Tab会根据规则关闭之前打开的Tab.但是可以通过设置来符合自己的使用习惯. 一.打开Tab过多自动关闭 1.选择File→ ...

  4. JSTL中forEach标签应用示例【转】【补】

    forEach样例 <%@ page language="java" import="java.util.*" pageEncoding="ut ...

  5. 直接用<img> 的src属性显示base64转码后的字符串成图片【原】

    直接用<img> 的src属性显示base64转码后的字符串成图片 <img src="data:image/gif;base64,base64转码后的字符串" ...

  6. Eclipse Groovy插件使用时出现的错误 org.eclipse.core.runtime.InvalidRegistryObjectException: Invalid registry object

    在eclipse marketplace中下载了groovy插件,发现使用的groovy版本跟项目中使用的groovy版本不一致. 于是在Preferences -> Groovy -> ...

  7. 在O(N)时间内求解 正数数组中 两个数相加的 最大值

    一,问题描述 给定一个正数数组arr(即数组元素全是正数),找出该数组中,两个元素相加的最大值,其中被加数的下标大于加数的下标.由加法运算的可逆性,j >i 这个条件可以去掉. 即求出: max ...

  8. oracle sum(x) over( partition by y ORDER BY z ) 分析

    之前用过row_number(),rank()等排序与over( partition by ... ORDER BY ...),这两个比较好理解: 先分组,然后在组内排名. 今天突然碰到sum(... ...

  9. nginx反向代理实现前后端分离&跨域问题

    1.代理和跨域 1.1 正向代理 1)用户希望代理服务器帮助其和要访问服务器之间实现通信,需要: a.用户IP报文的目的IP=代理服务器IP: b.用户报文端口号=代理服务器监听端口号: c.HTTP ...

  10. vlc-android 的编译过程

    参考官方文档:https://wiki.videolan.org/AndroidCompile#Get_VLC_Source 值得注意的的地方: 1.切记安装以下工具 sudo apt-get ins ...