jquery中,等待DOM加载完成再执行的方法ready事件,相信大家经常使用该事件,今天,我们来看下jquery源码中是如何实现该功能的。
首先看下,如何使用ready事件:
$(document).ready(function(){ console.log(1); });
等DOM加载完成后,执行匿名函数,在控制台中打印1。
首先了解一下DOMContentLoaded与window.load()。
DOMContentLoaded是DOM构建完成后触发,window.onload()是等所有的内容加载完成,例如图片等等。DOMContentLoaded事件先触发,后触发window.onload()事件。
jQuery.extend({ isReady: false, //DOM是否加载完毕,初始化为false readyWait: 1, //需要等待的事件,初始化为1 // Hold (or release) the ready event holdReady: function( hold ) { //是否要hold住ready事件。 }, // Handle when the DOM is ready ready: function( wait ) { //ready函数,执行ready事件是调用 } }); /** * The ready event handler and self cleanup method */ function completed() { //DOM完成后触发 } jQuery.ready.promise = function( obj ) { //ready事件调用的函数 }
jQuery.ready.promise();
jQuery.ready.promise = function( obj ) { if ( !readyList ) { //第一次执行时readylist为undefined,进入if readyList = jQuery.Deferred(); //readyList为Deferred对象 // 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" ) { //如果DOM已经加载完了,我们不再触发complete事件,直接走ready // Handle it asynchronously to allow scripts the opportunity to delay ready setTimeout( jQuery.ready ); } else { // Use the handy event callback document.addEventListener( "DOMContentLoaded", completed, false ); //给文档添加DOMContentLoaded事件 // A fallback to window.onload, that will always work window.addEventListener( "load", completed, false ); //如果DOMContentLoade不执行,以此为备用,总是执行 } } return readyList.promise( obj ); //返回状态不可改的Deferred对象 };
当工具方法都初始化完之后,开始执行$(document).ready()中的ready().
jQuery.fn.ready = function( fn ) { // Add the callback jQuery.ready.promise().done( fn ); //jQuery.ready.promise()函数,由于初始化工具方法时,已经执行过一遍,代码会直接返回Deferred对象。 return this; //把入参添加到done中 };
触发complete事件
function completed() { document.removeEventListener( "DOMContentLoaded", completed, false ); //去除绑定的函数 window.removeEventListener( "load", completed, false ); jQuery.ready(); //执行工具方法的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 ] ); //触发resolveWith执行done中添加的函数 // Trigger any bound ready events if ( jQuery.fn.triggerHandler ) { jQuery( document ).triggerHandler( "ready" ); jQuery( document ).off( "ready" ); } } });