https://demo.airtlab.com/browser/01-DomContentLoaded-and-Load
1. DOMContentLoaded
https://developer.mozilla.org/zh-CN/docs/Web/API/Window/DOMContentLoaded_event
MDN:当初始的 HTML 文档被完全加载和解析完成之后,DOMContentLoaded 事件被触发,而无需等待样式表、图像和子框架的完全加载。
提示:通过调试,我发现他这里的描述有误解,实际上头部中的样式的加载也会阻塞 DOMContentLoaded,也可能是我理解有误(请指出)。
当初始的 HTML 文档被完全加载和解析完成之后,DOMContentLoaded 事件被触发,而无需等待图像和子框架的完全加载。
DOMContentLoaded 事件阻塞相关:
- 脚本的加载和执行会阻塞 DOMContentLoaded (整个文档)
- 不需要等待 图片/子框架 等加载
- async defer script 不会阻塞 DOMContentLoaded
2. Load
https://developer.mozilla.org/zh-CN/docs/Web/API/Window/load_event
当整个页面及所有依赖资源,如样式表、图片、子框架等已完成加载时,将触发 load 事件,load 常常用于检测页面是否完全加载。
Load 事件阻塞相关:
- 如果资源是在异步任务中加载的,则不阻塞 Load,比如使用 setTimeout
- async defer script 会阻塞 Load
3. DOM 完整的解析过程
1、解析HTML结构。
2、加载外部脚本和样式表文件。
3、解析并执行脚本代码
4、DOM树构建完成,触发 DOMContentLoaded
5、加载图片等外部文件。
6、页面加载完毕,触发 Load
由于浏览器是边解析边执行,所以中间有些步骤是多次来回执行。
4. JQuery(document).ready 原理
1、监听 DOMContentLoaded 事件,注册 completed
2、completed 被执行时, 移除该事件,进入 ready
3、ready 被执行时,设置 isReady = true 进入 fire
4、fire 被执行时,fire callbacks(通过 ready 注册的回调)
// 使用
$(document).ready(function(){
console.log("ready");
})
// 1. DOMContentLoaded & load 注册回调
// Use the handy event callback
jQuery.ready.promise = function() {
if (!flag) {
document.addEventListener("DOMContentLoaded", completed);
// A fallback to window.onload, that will always work
window.addEventListener("load", completed);
}
}
// 2. 回调的调用成功后,注销绑定事件
/**
* The ready event handler and self cleanup method
*/
function completed() {
// readyState === "complete" is good enough for us to call the dom ready in oldIE
if ( document.addEventListener ||
window.event.type === "load" ||
document.readyState === "complete" ) {
detach();
jQuery.ready();
}
}
// 3. 进入 ready, 触发回调(readyList.resolveWith)
{
// Handle when the DOM is ready
ready: function( wait ) {
// Abort if there are pending holds or we're already ready
if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) {
return;
}
// Remember that the DOM is ready
jQuery.isReady = true;
// If a normal DOM Ready event fired, decrement, and wait if need be
if ( wait !== true && --jQuery.readyWait > 0 ) {
return;
}
// If there are functions bound, to execute
readyList.resolveWith( document, [ jQuery ] );
// Trigger any bound ready events
if ( jQuery.fn.triggerHandler ) {
jQuery( document ).triggerHandler( "ready" );
jQuery( document ).off( "ready" );
}
}
}
// 4. 进入 fire 方法,fire callbacks 将注册的事件一一执行
{
// Fire callbacks
fire = function() {
// Enforce single-firing
locked = options.once;
// Execute callbacks for all pending executions,
// respecting firingIndex overrides and runtime changes
fired = firing = true;
for ( ; queue.length; firingIndex = -1 ) {
memory = queue.shift();
while ( ++firingIndex < list.length ) {
// Run callback and check for early termination
if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false &&
options.stopOnFalse ) {
// Jump to end and forget the data so .add doesn't re-fire
firingIndex = list.length;
memory = false;
}
}
}
// Forget the data if we're done with it
if ( !options.memory ) {
memory = false;
}
firing = false;
// Clean up if we're done firing for good
if ( locked ) {
// Keep an empty list if we have data for future add calls
if ( memory ) {
list = [];
// Otherwise, this object is spent
} else {
list = "";
}
}
},
}
// 当我们使用 $(document).ready(fn) 会走这里
jQuery.fn.ready = function( fn ) {
// Add the callback
jQuery.ready.promise().done( fn );
return this;
};
网友评论