天天看点

jquery源码 DOM加载一、$(function(){})和原生window.onload的关系二、jQurey如何实现DOM ready的三、源码整体实现逻辑四、实现细节

jQuery版本:2.0.3

DOM加载有关的扩展

isReady:DOM是否加载完(内部使用) 

readyWait:等待多少文件的计数器(内部使用)

holdReady():推迟DOM触发

ready():准备DOM触发。

jQuery.ready.promise=function(){};  监听DOM的异步操作(内部使用)

这个在面试中也是经常会被问到的。从下面几个角度来分析一下它们的区别

页面加载,先加载节点,再加载文件,比如img文件,flash等。

$(function(){})DOM加载完执行。可能DOM元素关联的东西并没有加载完。

window.onload等节点和文件都加载完执行。

对应的事件监听

jQuery用的是DOMContentLoaded事件。

DOMDContentLoaded:原生DOM加载事件,这个事件触发代表DOM加载完了。

我之前写过一篇文章的页面加载时间分析里也有提到。

onload对应的是load事件。

window.onload不能写多个,后面的会覆盖前面的。

$(function(){})可以写多个。都会执行 。

$(function(){})是$(document) .ready(function(){});的简化写法。

window.onload没有简化写法。

jQuery直接调用DOMContentLoaded来实现DOM的ready。但是DOMContentLoaded和onLoad一样,浏览器只执行一次,jQuery用什么判断是否已经执行过呢?document.readyState就是判断这个的依据。

readyState是document的属性,总共有3个值:

loading:文档正在加载中

interactive:文档已经加载完成,正在进行css和图片等资源的加载

complete:文档的所以资源加载完成

判断完之后如何回调呢?就是用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)。也就是说

$(function(){}) =》

调用$(document).ready(function(){})=》

相当于$().ready(fn)实例方法=》

调用的jQuery.ready.promise().done(fn)=》

jQuery.ready.promise中不管if还是else最终都是调用jQuery.ready(),并返回promise=》

jQuery.ready()里面重点是readyList.resolveWith( document, [ jQuery ] );已完成。至此DOM加载完毕就可以调用fn了。

jquery源码 DOM加载一、$(function(){})和原生window.onload的关系二、jQurey如何实现DOM ready的三、源码整体实现逻辑四、实现细节

如果DOM已经加载完成了,调用jQuery.ready()这个工具方法;

如果DOM没加载完,监听DOMContentLoaded事件和load事件,等事件发生时回调completed(),最终也是调用jQuery.ready()这个工具方法;

completed回调函数如下,最终调用的也是jQuery.ready()。 

先做个测试:

jquery源码 DOM加载一、$(function(){})和原生window.onload的关系二、jQurey如何实现DOM ready的三、源码整体实现逻辑四、实现细节

再做个测试:

除了$(function(){});$(document).ready(function(){}),也可以把ready当做事件来处理如下。

之所以会自动弹出123,是因为在jQuery源码中用这句话jQuery( document ).trigger("ready").off("ready");来主动触发了ready事件,触发后再取消掉。

跟ready的参数有关的有一个holdReady()。

先做个测试

可以推迟,也可以释放推迟,释放了以后就可以触发了。

这个有什么用?

比如:

很多时候引入外部文件的时候,都想等外部文件或者插件加载完,再去触发操作,操作可能用到a.js。现在这个顺序不对,会出问题。

怎样解决这个问题?用holdReady()方法。

再深入一点,holdReady() 要针对的文件可能不止一个,有很多个,所以要等所有的文件都加载完再执行,所以源码中有一个计数的readyWait。

源码中定义了一个等待栈变量——readyWait,每次执行$.holdReady(true)都会增加压栈,而每次$.holdReady()执行都会弹栈,等空栈的时候就执行jQuery.ready函数,即将promise给resolve掉。

本文转自帅气的头头博客51CTO博客,原文链接http://blog.51cto.com/12902932/1926151如需转载请自行联系原作者

sshpp

继续阅读