一、何时触发这两个事件?

1、当 onload 事件触发时,页面上所有的DOM,样式表,脚本,图片,flash都已经加载完成了。

2、当 DOMContentLoaded 事件触发时,仅当DOM加载完成,不包括样式表,图片,flash。

二、为什么要区分?

开发中我们经常需要给一些元素的事件绑定处理函数。但问题是,如果那个元素还没有加载到页面上,但是绑定事件已经执行完了,是没有效果的。这两个事件大致就是用来避免这样一种情况,将绑定的函数放在这两个事件的回调中,保证能在页面的某些元素加载完毕之后再绑定事件的函数。

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

这里又要牵扯到页面加载渲染的原理了:

1、加载样式表会阻塞外链脚本的执行

  一些Gecko和Webkit引擎版本的浏览器,包括IE8在内,会同时发起多个Http请求来并行下在样式表和脚本。但脚本不会被执行,直到样式被加载完成。在未加载完之前甚至页面也不会被渲染。但是在opera中样式的加载不会阻塞脚本的执行。

  因此:目前通用的作法是把脚本和样式都以外链形式引入,甚至在jquery的官方文档中也是这样推荐的。对于大部分脚本来说,这样的脚本等待外链的机制还是有意义的,比如一些DOM和样式操作需要读取元素的位置,颜色等。这就需要样式先于脚本加载

检验方法:尝试强制使服务器端使style延迟一段时间才加载(甚至10秒),测试的结果是,在某些版本的Firefox,Chrome中最后一段脚本仍然是可以读出style的属性值(因为style始终先于javascript加载),比如#FF0000或者rgb(255, 0, 0),而这验证了我上面的说法。而在opera中却无法读出style的属性。代码如下:

html 文件内容
<!DOCTYPE html>
<head>
<linkrel="stylesheet"href="stylesheet.css">
<scriptsrc="script.js"></script>
</head>
<body>
<divid="element">The element</div><
/body>
</html> stylesheet.css 文件内容
#element { color: red; } script.js文件内容
document.addEventListener('DOMContentLoaded',function(){
alert(getComputedStyle(document.getElementById('element'),null).color);},
false);

2、各大javascript框架如何实现domReady事件的

早期版本的浏览器是没有DOMContentLoaded事件的那么它们怎么模拟实现类似功能呢?先来说说原理

(1)、如果是webkit引擎则轮询document的readyState属性,当值为loaded或者complete时则触发DOMContentLoaded事件,对webkit525之后版本直接可以注册DOMContentLoaded事件

if(Browser.Engine.webkit){
timer = window.setInterval(function(){
  if(/loaded|complete/.test(document.readyState))
fireContentLoadedEvent();
  },0);
}

(2)、IE处理方式有多种

a、在页面临时插入一个script元素,并设置defer属性,最后把该脚本加载完成视作DOMContentLoaded事件来触发。这样做有一个问题是,如果插入脚本的页面包含iframe的话,会等到iframe加载完才触发,其实这与onload是无异的。即这个方法不准确。

b、通过setTiemout来不断的调用documentElement的doScroll方法,直到调用成功则出触发DOMContentLoaded。这样做的原理是在IE下,DOM的某些方法只有在DOM解析完成后才可以调用,doScroll就是这样一个方法,反过来当能调用doScroll的时候即是DOM解析完成之时,与prototype中的document.write相比,该方案可以解决页面有iframe时失效的问题

c、首先注册document的onreadystatechange事件,但经测试后该方法与window.onload相当,效果不大。下面是jquery做的兼容性处理代码。

document.attachEvent("onreadystatechange",
  function(){
    if( document.readyState ==="complete"){
   document.detachEvent("onreadystatechange", arguments.callee );
jQuery.ready();}
});

接下来具体看一看几大前端框架是如何综合运用这几个方法的。

jQuery.ready.promise = function( obj ) {//定义一个状态机
if ( !readyList ) {//保证页面只创建一个延迟对象,多次使用$.ready() 则直接使用延迟对象done方法加入回调队列 readyList = jQuery.Deferred();//异步延迟对象
       // readyRE = /complete|loaded|interactive/,
// Catch cases where $(document).ready() is called after the browser event has already occurred.
// we once tried to use readyState "interactive" here, but it caused issues like the one
// discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15
if ( document.readyState === "complete" ) {//

          这个属性是只读的,传回值有以下的可能:

          //0-UNINITIALIZED:XML 对象被产生,但没有任何文件被加载。 
          //1-LOADING:加载程序进行中,但文件尚未开始解析。 
          //2-LOADED:部分的文件已经加载且进行解析,但对象模型尚未生效。 
          //3-INTERACTIVE:仅对已加载的部分文件有效,在此情况下,对象模型是有效但只读的。 
          //4-COMPLETED:文件已完全加载,代表加载成功

// Handle it asynchronously to allow scripts the opportunity to delay ready
setTimeout( jQuery.ready ); // Standards-based browsers support DOMContentLoaded
} else if ( document.addEventListener ) {//符合W3C标准的浏览器
// Use the handy event callback
document.addEventListener( "DOMContentLoaded", completed, false ); // A fallback to window.onload, that will always work
window.addEventListener( "load", completed, false );//还是给load事件注册了事件,以防不测,做为回滚用 // If IE event model is used
} else {
// Ensure firing before onload, maybe late but safe also for iframes
document.attachEvent( "onreadystatechange", completed ); // A fallback to window.onload, that will always work
window.attachEvent( "onload", completed ); // If IE and not a frame
// continually check to see if the document is ready
var top = false; try {//判断是否为iframe,如果不是的话采用不断的轮询scorll的方法
top = window.frameElement == null && document.documentElement;
} catch(e) {} if ( top && top.doScroll ) {
(function doScrollCheck() {
if ( !jQuery.isReady ) { try {
// Use the trick by Diego Perini
// http://javascript.nwbox.com/IEContentLoaded/
top.doScroll("left");
} catch(e) {
return setTimeout( doScrollCheck, 50 );
} // detach all dom ready events
detach(); // and execute any waiting functions
jQuery.ready();//实际:readyList.resolveWith( document, [ jQuery ] );
                    }
})();
}
}
}
return readyList.promise( obj );
};

再贴上几段其他框架的代码,大同小异,就不具体分析了

prototype

(function(GLOBAL) {
/* Support for the DOMContentLoaded event is based on work by Dan Webb,
Matthias Miller, Dean Edwards, John Resig, and Diego Perini. */ var TIMER; function fireContentLoadedEvent() {
if (document.loaded) return;
if (TIMER) window.clearTimeout(TIMER);
document.loaded = true;
document.fire('dom:loaded');
} function checkReadyState() {
if (document.readyState === 'complete') {
document.detachEvent('onreadystatechange', checkReadyState);
fireContentLoadedEvent();
}
} function pollDoScroll() {
try {
document.documentElement.doScroll('left');
} catch (e) {
TIMER = pollDoScroll.defer();
return;
} fireContentLoadedEvent();
} if (document.readyState === 'complete') {
// We must have been loaded asynchronously, because the DOMContentLoaded
// event has already fired. We can just fire `dom:loaded` and be done
// with it.
fireContentLoadedEvent();
return;
} if (document.addEventListener) {
// All browsers that support DOM L2 Events support DOMContentLoaded,
// including IE 9.
document.addEventListener('DOMContentLoaded', fireContentLoadedEvent, false);
} else {
document.attachEvent('onreadystatechange', checkReadyState);
if (window == top) TIMER = pollDoScroll.defer();
} // Worst-case fallback.
Event.observe(window, 'load', fireContentLoadedEvent);
})(this);

mootools

(function(GLOBAL) {
/* Support for the DOMContentLoaded event is based on work by Dan Webb,
Matthias Miller, Dean Edwards, John Resig, and Diego Perini. */ var TIMER; function fireContentLoadedEvent() {
if (document.loaded) return;
if (TIMER) window.clearTimeout(TIMER);
document.loaded = true;
document.fire('dom:loaded');
} function checkReadyState() {
if (document.readyState === 'complete') {
document.detachEvent('onreadystatechange', checkReadyState);
fireContentLoadedEvent();
}
} function pollDoScroll() {
try {
document.documentElement.doScroll('left');
} catch (e) {
TIMER = pollDoScroll.defer();
return;
} fireContentLoadedEvent();
} if (document.readyState === 'complete') {
// We must have been loaded asynchronously, because the DOMContentLoaded
// event has already fired. We can just fire `dom:loaded` and be done
// with it.
fireContentLoadedEvent();
return;
} if (document.addEventListener) {
// All browsers that support DOM L2 Events support DOMContentLoaded,
// including IE 9.
document.addEventListener('DOMContentLoaded', fireContentLoadedEvent, false);
} else {
document.attachEvent('onreadystatechange', checkReadyState);
if (window == top) TIMER = pollDoScroll.defer();
} // Worst-case fallback.
Event.observe(window, 'load', fireContentLoadedEvent);
})(this);

纸上学来终觉浅,绝知此事要躬行。自己写一段。

(function(window,undefined){
hobo = {}
var readyList = [],
_isReady =false; function readyFn(){
console.log(event.type)
if ( document.addEventListener || event.type === "load" || document.readyState === "complete" ) {
detach(); _isReady =true; fireReady();
        

}
}
    
  function fireReady(){
      for (var i = 0,fn; fn = readyList[i++];) {
fn();
};
      readyList = null;
      fireReady = function(){}//惰性函数,防止IE9二次调用
  }

    function detach() {
if ( document.addEventListener ) { document.removeEventListener( "DOMContentLoaded", readyFn, false );
window.removeEventListener( "load", readyFn, false ); } else {
document.detachEvent( "onreadystatechange", readyFn );
window.detachEvent( "onload", readyFn );
}
} hobo.ready = function(fn){
if(readyList){
readyList.push(fn)
} if(readyList.length>1){
return;
} if(document.readyState === 'complete'){
setTimeout(readyFn);
}else if (document.addEventListener) {//符合W3C 则监听 DOMContentLoaded和load事件
console.log('addEventListener')
document.addEventListener('DOMContentLoaded',readyFn,false);
document.addEventListener('DOMContentLoaded',readyFn,false);
}else{//针对IE
console.log('attachEvent')
document.attachEvent('onreadystatechange',readyFn); document.attachEvent('onload',readyFn);
} //针对IE并且非frame
var top = false;
try{
top = window.frameElement===null&&document.documentElement
}catch(e){} if(top&&top.doScroll){
(function doScrollCheck(){
if (!_isReady) {
try {//每隔50秒轮询 检测是否支持doScroll()方法
top.doScroll("left");
} catch(e) {
return setTimeout( doScrollCheck, 50 );
}
};
})
} }
window.hobo =hobo
}(window,void 0)) //使用 hobo.ready(function(){
console.log(11111);
})
hobo.ready(function(){
console.log(22222);
})

DOMContentLoaded 与onload区别以及使用的更多相关文章

  1. onreadystatechange和onload区别分析

    onreadystatechange和onload区别分析   script加载 IE的script 元素只支持onreadystatechange事件,不支持onload事件. FireFox,Op ...

  2. ready与onload区别一

    <!DOCTYPE html><html> <head> <title>ready与onload区别一</title> <meta c ...

  3. jquery中read与js中onload区别

    在JavaScript中,onload函数是最经常使用的,几乎涉及到JavaScript的童鞋都少不了要接触它.这个函数的作用就是等待网页完全装载完了以后再去执行代码块内的语句,因为按照文档流的执行顺 ...

  4. jquery的$(document).ready()与js的window.onload区别

    <!DOCTYPE html> <html lang="en" xmlns="http://www.w3.org/1999/xhtml"> ...

  5. window.load 和$(document).ready() 、window.load和body onload区别

    1.执行时间 window.onload必须等到页面内包括图片的所有元素加载完毕后才能执行. $(document).ready()是DOM结构绘制完毕后就执行,不必等到加载完毕.2.编写个数不同 w ...

  6. $.ready和onload 区别

    1.jq ready()的方法就是Dom Ready 他的作用或者意义就是:在DOM加载完成后就可以可以对DOM进行操作. 一般情况先一个页面响应加载的顺序是,域名解析-加载html-加载js和css ...

  7. jq中$(function(){})和js中window.onload区别

    先看下执行代码: $(function(){   console.log("jq");}) $(function(){   console.log("jq1") ...

  8. $(document).ready,$(window).load,window.onload区别和联系

    $(document).ready是在dom结构加载完毕就执行. $(window).load 等价于window.onload,必须等到页面内包括图片的所有元素加载完毕后才能执行. $(docume ...

  9. $(document).ready()方法和window.onload区别

    事件: javascript 和 HTML之间的交互式通过用户和浏览器操作页面时引发的事件来处理的.当文档或者它的某些元素发生某些变化和操作时,浏览器会自动生成一个事件:例如:当用户单击某个按钮时,也 ...

随机推荐

  1. lightbox2

    http://lokeshdhakar.com/projects/lightbox2/ 简单的demo <html> <head id="head"> &l ...

  2. [BZOJ 2199] 奶牛议会

    [题目链接] https://www.lydsy.com/JudgeOnline/problem.php?id=2199 [算法] 2-SAT [代码] #include<bits/stdc++ ...

  3. mahjong

    题目描述 “为什么, 你们的力量在哪里得到如此地......”“我们比 1 分钟前的我们还要进步, 虽然很微小, 但每转一圈就会前进一寸.这就是钻头啊!”“那才是通向毁灭的道路.为什么就没有意识到螺旋 ...

  4. Coursera公开课-Machine_learing:编程作业7

    这周的编程作业主要是两方面内容. 1.K-means聚类. 2.PCA(Principle Component Analys)主成分分析. 方式主要是通过对图像的聚类实现压缩图像,后来发现PCA也可以 ...

  5. Jquery课堂上课了,第一节Jquery选择器$

    Jquery是优秀的Javascrīpt框架,$是jquery库的申明,它很不稳定(我就常遇上),换一种稳定的写法jQuery.noConflict();                   jQue ...

  6. Unity学习-地形的设置(五)

    添加地形游戏对象 [Hierarchy-Create-Terrain] 为了看的看清楚,在添加一个平行光 [Hierarchy-Create-Direction light] 导入地形包 [Asset ...

  7. MVC系列学习(十)-生成URL与表单

    本次学习,在路由配置信息中,有两个路由规则,在网站第一次启动的时候,注册了两个路由表 1.动态生成url A.在路由规则中,因为Default在前面,所以最新找到该路由表,此时不管 自己定义的控制器名 ...

  8. [ Nowcoder Contest 165 #D ] 合法括号序列

    \(\\\) \(Description\) 键盘上有三个键,敲击效果分别是: 在输出序列尾部添加一个左括号 在输出序列尾部添加一个右括号 删除输出序列尾部的第一个元素,若输出序列为空,则什么都不发生 ...

  9. html中保证中文能够正常显示

    <meta http-equiv="Content-Type" content="text/html"; charset=utf-8"/> ...

  10. Java类加载机制总结

    关于Java类加载机制的几个基本概念: JDK提供的基本类加载器:引导类加载器(Bootstrap Class Loader)-用于加载JDK中的核心类.扩展类加载器(Ext Class Loader ...