> 脚本语言 > >
jquery源码DOM加载 2017-05-16 17:59 出处:清屏网 人气:
jQuery版本:2.0.3
DOM加载有关的扩展
这个在面试中也是经常会被问到的。从下面几个角度来分析一下它们的区别
1、执行时机页面加载,先加载节点,再加载文件,比如img文件,flash等。
$(function(){})DOM加载完执行。可能DOM元素关联的东西并没有加载完。
window.onload等节点和文件都加载完执行。
对应的事件监听jQuery用的是DOMContentLoaded事件。
DOMDContentLoaded:原生DOM加载事件,这个事件触发代表DOM加载完了。
我之前写过一篇文章的页面加载时间分析里也有提到。
onload对应的是load事件。
2、个数window.onload不能写多个,后面的会覆盖前面的。
$(function(){})可以写多个。都会执行 。
3、简化写法$(function(){})是$(document) .ready(function(){});的简化写法。
window.onload没有简化写法。
二、jQurey如何实现DOM ready的jQuery直接调用DOMContentLoaded来实现DOM的ready。但是DOMContentLoaded和onLoad一样,浏览器只执行一次,jQuery用什么判断是否已经执行过呢?document.readyState就是判断这个的依据。
readyState是document的属性,总共有3个值:
判断完之后如何回调呢?就是用Promise。jQuery通过new一个$.Deferred(promise)对象来实现对DOM的ready的回调,在 DOMContentLoaded中将这个promise给resolve掉 ,这样就执行了之前注册的回调函数,同时后面新注册的回调也会立刻执行。
但是在调用promise之前,jQuery执行了一次setTimeout,因为jQuery.Promise是不会产生异步的,这和标准的promise规范是不一样的,所有jQuery自己又手动做了一次setTimeout来实现异步。这样使得无论使用在DOM的ready之前注册的回调还是之后注册的回调都会在 异步中执行。
三、源码整体实现逻辑$(fn)==>new一个 jQuery. fn. init(fn )==>返回 $(document). ready( fn) 。也就是说
四、实现细节 1、重点是:jQuery.ready.promise()方法【 巧妙 】
如果DOM已经加载完成了,调用jQuery.ready()这个工具方法;
如果DOM没加载完,监听DOMContentLoaded事件和load事件,等事件发生时回调completed(),最终也是调用jQuery.ready()这个工具方法;
var // A central reference to the root jQuery(document) rootjQuery, // The deferred used on DOM ready readyList; jQuery.ready.promise = function( obj ) { if ( !readyList ) { //第一次readyList为空可以进来,后续就进不来if了,只执行一次 readyList = jQuery.Deferred(); //第一步,创建延迟对象 if ( document.readyState === "complete" ) { //DOM加载完成的标志就是document.readyState为complete,如果DOM已经加载好了就直接调工具方法jQuery.ready。 setTimeout( jQuery.ready );//加定时器是为了兼容IE } else {//DOM没有加载完检测,即检测了DOMContentLoaded事件,也检测了load事件;最终走回调completed函数 // 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事件,为了第一时间相应所以对load也监听了 } } return readyList.promise( obj ); };completed回调函数如下,最终调用的也是jQuery.ready()。
// The ready event handler and self cleanup method completed = function() { //不管是DOMContentLoaded事件还是load发生,都会取消2个事件监听 //jQuery.ready()只会触发一次 document.removeEventListener( "DOMContentLoaded", completed, false ); window.removeEventListener( "load", completed, false ); jQuery.ready(); }; 2、jQuery.ready()工具方法做了些什么先做个测试:
$(function(arg){ alert(this); //[object HTMLDocument] alert(arg); //jQuery函数 })
再做个测试:
除了$(function(){});$(document).ready(function(){}),也可以把ready当做事件来处理如下。
<script> $(document).on("ready",function(){ alert(123); //123 }); </script>之所以会自动弹出123,是因为在jQuery源码中用这句话jQuery( document ).trigger("ready").off("ready");来主动触发了ready事件,触发后再取消掉。
// Handle when the DOM is ready ready: function( wait ) { //参数和holdReady有关 // 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; } //第一步看这里重点,resolveWith改变状态的时候传参了,给done中方法fn传入了参数, //document是fn的this指向,jQuery是参数 // If there are functions bound, to execute readyList.resolveWith( document, [ jQuery ] ); //跟主动触发有关 // Trigger any bound ready events if ( jQuery.fn.trigger ) { jQuery( document ).trigger("ready").off("ready"); } },跟ready的参数有关的有一个holdReady()。
先做个测试
$.holdReady(true); $(function () { alert(123); //调用了holdReady并传参true,就不能弹出123了 });可以推迟,也可以释放推迟,释放了以后就可以触发了。
$.holdReady(true); $.holdReady(false); $(function () { alert(123); //释放了holdReady,就弹出123 });这个有什么用?