DOMContentLoaded VS onload VS onreadystatechange

1. DOMContentLoaded 在页面html、script、style加载完毕即可触发,无需等待所有资源(image/iframe)加载完毕。(IE9+)

2. onload是最早支持的事件,要求所有资源加载完毕触发。

3. onreadystatechange 开始在IE引入,后来其它浏览器也有一定的实现。涉及以下 document , applet, embed, frame, frameset, iframe, img, input:image, link, script, xml
标签的元素,都触发该事件。通常来讲,会有 loading /interactive/complete几个状态值。
对于页面加载完毕,检测的是 document.readystate === "complete" 状态。就目前IE6~8的测试结果来看,这个事件的触发约[b]等同于[/b] onload 事件,[b]触发顺序[/b]上onload在后面。

其它需要注意的是:
1. [b]IE11+[/b],对于script标签,onreadystatechange不再受支持,请用onload来判断js的加载完成。
(查看;https://msdn.microsoft.com/en-us/library/ms536957(v=vs.85).aspx)


2. 在IE中,document.readystate === "interactive" ,在图片、js加载完成之前就已经触发,所以不能用来模拟 DOMContentLoaded 事件。

// 模拟DOMContentLoaded ------- 不要这样用,这是错误的。
document.onreadystatechange = function () {
if (document.readyState == "interactive") {
initApplication();
}
}

(示例代码源自:https://developer.mozilla.org/zh-CN/docs/Web/API/Document/readyState 。)


3. 如果你在onload的事件函数里面,再次监听 onload事件,那么,是不会再次触发函数的。

function addOnload(callback) {
if ( "undefined" != typeof(window.attachEvent) ) {
return window.attachEvent("onload", callback);
}
else if ( window.addEventListener ){
return window.addEventListener("load", callback, false);
}
}

function onload1() {
document.getElementById('results').innerHTML += "First onload executed.";

//没用的,onload2是不会被调用的.
addOnload(onload2);
}

function onload2() {
document.getElementById('results').innerHTML += "Second onload executed.";
}

addOnload(onload1);

(查看:http://www.stevesouders.com/blog/2014/09/12/onload-in-onload/)
因此,对于异步加载的JS,为了保证js能在onload里面触发,可以先判断 [b]document.readystate === "complete"[/b],如果成功,则立即执行函数。

4. 最后,看看jQuery1.8里面,有关 ready 函数的实现:


// The ready event handler and self cleanup method
DOMContentLoaded = function() {
if ( document.addEventListener ) {
document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false );
jQuery.ready();
} else if ( document.readyState === "complete" ) {
// we're here because readyState === "complete" in oldIE
// which is good enough for us to call the dom ready!
document.detachEvent( "onreadystatechange", DOMContentLoaded );
jQuery.ready();
}
},



jQuery.ready.promise = function( obj ) {
if ( !readyList ) {

readyList = jQuery.Deferred();

// Catch cases where $(document).ready() is called after the
// browser event has already occurred.
if ( document.readyState === "complete" || ( document.readyState !== "loading" && document.addEventListener ) ) {
// Handle it asynchronously to allow scripts the opportunity to delay ready
setTimeout( jQuery.ready, 1 );

// Standards-based browsers support DOMContentLoaded
} else if ( document.addEventListener ) {
// Use the handy event callback
document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false );

// A fallback to window.onload, that will always work
window.addEventListener( "load", jQuery.ready, false );

// If IE event model is used
} else {
// Ensure firing before onload, maybe late but safe also for iframes
document.attachEvent( "onreadystatechange", DOMContentLoaded );

// A fallback to window.onload, that will always work
window.attachEvent( "onload", jQuery.ready );

// If IE and not a frame
// continually check to see if the document is ready
var top = false;

try {
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 );
}

// and execute any waiting functions
jQuery.ready();
}
})();
}
}
}
return readyList.promise( obj );
};




https://msdn.microsoft.com/en-us/library/ms536957(v=vs.85).aspx
https://github.com/dperini/ContentLoaded/blob/master/src/contentloaded.js
https://developer.mozilla.org/zh-CN/docs/Web/API/Document/readyState
http://www.stevesouders.com/blog/2014/09/12/onload-in-onload/
<think>好的,我现在需要帮助用户解决如何在window.onload事件触发前执行函数的问题。根据用户提供的引用内容,我需要先理解现有的信息,然后结合相关知识提出解决方案。 首先,用户提到的引用[1]指出,在IE中可以使用defer属性来延迟脚本执行,直到文档加载完成。这可能类似于window.onload,但只在IE有效。引用[3]提到了$(document).ready()window.onload的区别,说明前者在DOM就绪后执行,而后者要等所有资源加载完毕。这提示可能有其他方法在DOM准备就绪时提前执行代码。 用户的需求是在window.onload之前运行函数。通常,window.onload会在页面所有资源(如图片、样式表)加载完成后触发,而DOMContentLoaded事件则在DOM树构建完成后触发,不需要等待外部资源。因此,使用DOMContentLoaded事件可能是一个解决方案。此外,jQuery的$(document).ready()也是基于这个事件,所以可以推荐这两种方法。 另外,引用[1]提到的defer属性虽然只适用于IE,但现代浏览器也支持defer,它会让脚本在DOM解析完成后、DOMContentLoaded之前执行。这可能也是一个方法,但需要考虑兼容性。 用户可能需要兼容不同浏览器的解决方案,所以需要综合使用DOMContentLoadedreadystatechange事件来覆盖更多情况。例如,监听document的readystatechange事件,当状态变为interactive时执行函数,这样可以在DOM准备好后立即执行,而不必等待所有资源。 还有,内联脚本或放在<head>中的脚本,使用defer或async属性可能会影响执行时机。但需要注意,defer脚本会在DOMContentLoaded之前执行,而async则可能随时执行,无法保证顺序。 总结可能的解决方案: 1. 使用DOMContentLoaded事件。 2. 使用jQuery的$(document).ready()。 3. 使用readystatechange事件检测document.readyState是否为interactive或complete。 4. 在页面顶部放置同步的<script>标签,但可能阻塞渲染。 5. 使用defer属性延迟脚本执行,但需注意兼容性。 需要验证这些方法的执行顺序兼容性,确保在window.onload之前执行。同时,要处理不支持某些事件的老旧浏览器,可能需要回退到其他方法。 现在需要将这些思路整理成步骤,给出具体的代码示例,并引用提供的参考资料中的内容,比如引用[1]的defer引用[3]的document.ready方法。</think>### 如何在 `window.onload` 触发前运行函数? #### 方法一:使用 `DOMContentLoaded` 事件 `DOMContentLoaded` 事件在 HTML 文档解析完成(DOM 树构建完毕)时触发,无需等待样式表、图片等外部资源加载。这比 `window.onload` 触发更早。 ```javascript document.addEventListener('DOMContentLoaded', function() { console.log('DOM 已加载,早于 window.onload'); }); ``` #### 方法二:使用 `jQuery` 的 `$(document).ready()` 原理与 `DOMContentLoaded` 相同,但兼容性更好(尤其对老旧浏览器)[^3]。 ```javascript $(document).ready(function() { console.log('DOM 就绪,早于 window.onload'); }); ``` #### 方法三:监听 `readystatechange` 事件 通过检测 `document.readyState` 状态实现更细粒度的控制: - `interactive`:DOM 解析完成,但资源可能未加载完。 - `complete`:所有资源加载完成(等同于 `window.onload`)。 ```javascript document.onreadystatechange = function() { if (document.readyState === 'interactive') { console.log('DOM 解析完成,资源加载中'); } }; ``` #### 方法四:直接内联脚本或同步脚本 将脚本直接放在 `<body>` 开头或 `<head>` 中(无 `defer`/`async` 属性),此时脚本会在 DOM 解析时同步执行,但会阻塞渲染。 ```html <script> console.log('内联脚本立即执行'); </script> ``` #### 方法五:使用 `defer` 属性(部分场景适用) 带有 `defer` 属性的脚本会在 DOM 解析完成后、`DOMContentLoaded` 触发前执行,但仅对外部脚本有效[^1]。 ```html <script src="deferred-script.js" defer></script> ``` --- ### 执行顺序总结 1. 同步脚本(内联或非异步外部脚本) 2. `DOMContentLoaded` 事件或 `$(document).ready()` 3. `defer` 脚本(按文档顺序执行) 4. `window.onload` 事件 --- ### 替代方案:预加载关键函数 若需在页面渲染前执行逻辑(如资源预加载),可结合 `Preload` 或 `Prefetch`: ```html <link rel="preload" href="critical.js" as="script"> ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值