一、前言

  在平时开发web项目时,我们使用jquery框架时,可能经常这样来使用$(document).ready(fn),$(function(){}),这样使用的原因是在浏览器把DOM树渲染好之前,javascript是无法操作没渲染好的DOM节点。

  其实除了$(document).ready(fn),$(function(){})写法外,还有两种让dom渲染完之后执行js的写法:

$(document).on('ready', fn2)  //通过on事件绑定函数,通过trigger触发也可以达到

jQuery.ready.promise().done(fn); //通过这种方式也可以实现,jQuery.ready.promise()返回一个deferred对象,done(fn)添加回调方法

  其中具体流程图如下(自己简单画了一下,有错请大家指正)

  

二、源码部分(建议看这部分是,先理解清楚deferred,promise)

  ①$(function(){}) =>到rootjQuery.ready(selector);

  我们知道,jQuery是由new jQuery.fn.init(selector, context, rootjQuery)实例出来的,对接了两个参数,selector,context

 // 构造函数,定义一个局部变量的jQuery
jQuery = function (selector, context) {
// jQuery对象实际上是init的构造函数的引用
return new jQuery.fn.init(selector, context, rootjQuery);
}

  当我们使用$(function(){}),则选择器selector参数就变成了funciton,jQuery.fn.init函数判断selector为Funtion时,又指向了rootjQuery.ready(selector),就是$(document).ready(fn);

rootjQuery = $(document)
jQuery.fn = jquery.prototype = {
  init:function(selector,context,rootjQuery){
if (jQuery.isFunction(selector)) {
// 引用非静态成员ready方法,等价于$(document).ready(selector)
return rootjQuery.ready(selector);
}
  }
  } 

  ②$(document).on("ready",fn) => 到jQuery(document).trigger("ready").off("ready");

  要理解$(document).on("ready",fn),我们要看ready部分

    //扩展方法到jquery****************************************
jQuery.extend({
/**
记录监听DOMContentLoaded事件(DOM是否加载完成),加载完成设置为true(类似一个开关)
* type {Boolean} 默认为false,表示页面未加载完。当页面DOM加载完成,设置为true
*/
isReady: false, /**
需要预加载的观察者数量
* type {Number} 观察者数量
*/
readyWait: , /**
DOM加载完成,执行预加载
* @param {Boolean} wait 为true表示锁定委托人,为false表示释放委托人
*/
ready: function (wait) { if (wait === true ? --jQuery.readyWait : jQuery.isReady) {
return;
} // 检测body是否存在(IE的一个bug),存在继续向下执行,不存在进入语句,执行setTimeout定时器,直到body存在
if (!document.body) {
return setTimeout(jQuery.ready);
} // 开关,记录DOM加载完成
jQuery.isReady = true; // 检测所有的观察者是否执行完成
if (wait !== true && --jQuery.readyWait > ) {
return;
} // 委托人readyList通知观察者,开始执行回调函数,并将document作为这些函数的上下文环境
readyList.resolveWith(document, [jQuery]); // 检测trigger方法是否存在,触发绑定在document上的事件,执行完成之后并解绑
// $(document).on('ready', fn2);
// $(document).ready(fn1);
//这里的fn1会先执行,自己的ready事件绑定的fn2回调后执行
if (jQuery.fn.trigger) {
jQuery(document).trigger("ready").off("ready");
}
}
})

  ③$(document).ready(fn)

    jQuery.fn = jquery.prototype = {
if (jQuery.isFunction(selector)) {
// 引用非静态成员ready方法
return rootjQuery.ready(selector);
},
ready: function (fn) {
// Add the callback
// promise类似一种事件委托,相当于一个创建委托人(已创建则无需创建,通过readyList判断是否已创建),在DOM加载完成之后,委托人会通知观察者done去执行回调函数fn
//调委托函数,返回deferred对象,添加done(fn)回调函数
jQuery.ready.promise().done(fn); return this;
}
}

最后dom ready相关部分源码详细如下:

 // 构造函数,定义一个局部变量的jQuery
jQuery = function (selector, context) {
// jQuery对象实际上是init的构造函数的引用
return new jQuery.fn.init(selector, context, rootjQuery);
} // 就绪事件处理程序
completed = function (event) { // document.readyState 判断文档加载状态,'complete'代表文档已经完全加载 if (document.addEventListener || event.type === "load" || document.readyState === "complete") { detach(); //清理方法 jQuery.ready();//执行延迟加载方法
}
} // 清理DOMContentLoaded事件处理程序,为DOM事件做好准备,触发jQuery.ready方法
detach = function () {
// 标准的W3C监听事件
if (document.addEventListener) {
//删除DOMContentLoaded监听事件
document.removeEventListener("DOMContentLoaded", completed, false);
window.removeEventListener("load", completed, false);
} else {
// 针对IE,非标准的浏览器
// 删除onreadystatechange监听事件
document.detachEvent("onreadystatechange", completed);
window.detachEvent("onload", completed);
}
};
var readyList,rootjQuery=$(document);
jQuery.fn = jquery.prototype = {
if (jQuery.isFunction(selector)) {
// 引用非静态成员ready方法
return rootjQuery.ready(selector);
},
ready: function (fn) {
// Add the callback
// promise类似一种事件委托,相当于一个创建委托人(已创建则无需创建,通过readyList判断是否已创建),在DOM加载完成之后,委托人会通知观察者done去执行回调函数fn
//调委托函数,返回deferred对象,添加done(fn)回调函数
jQuery.ready.promise().done(fn); return this;
}
} //扩展方法到jquery****************************************
jQuery.extend({
/**
记录监听DOMContentLoaded事件(DOM是否加载完成),加载完成设置为true(类似一个开关)
* type {Boolean} 默认为false,表示页面未加载完。当页面DOM加载完成,设置为true
*/
isReady: false, /**
需要预加载的观察者数量
* type {Number} 观察者数量
*/
readyWait: , /**
锁定或释放预加载委托人
* @param {Boolean} hold 为true表示锁定预加载委托人,为false表示释放委托人
*/
holdReady: function (hold) {
if (hold) {
jQuery.readyWait++;
} else {
jQuery.ready(true);
}
}, /**
DOM加载完成,执行预加载
* @param {Boolean} wait 为true表示锁定委托人,为false表示释放委托人
*/
ready: function (wait) { // Abort if there are pending holds or we're already ready
if (wait === true ? --jQuery.readyWait : jQuery.isReady) {
return;
} // 检测body是否存在(IE的一个bug),存在继续向下执行,不存在进入语句,执行setTimeout定时器,直到body存在
if (!document.body) {
return setTimeout(jQuery.ready);
} // 开关,记录DOM加载完成
jQuery.isReady = true; // 检测所有的观察者是否执行完成
if (wait !== true && --jQuery.readyWait > ) {
return;
} // 委托人readyList通知观察者,开始执行回调函数,并将document作为这些函数的上下文环境
readyList.resolveWith(document, [jQuery]); // 检测trigger方法是否存在,触发绑定在document上的事件,执行完成之后并解绑
// $(document).on('ready', fn2);
// $(document).ready(fn1);
//这里的fn1会先执行,自己的ready事件绑定的fn2回调后执行
if (jQuery.fn.trigger) {
jQuery(document).trigger("ready").off("ready");
}
}
}) // 预加载委托函数
jQuery.ready.promise = function (obj) {
// 判断预加载委托人是否存在
if (!readyList) {
// 创建一个预加载委托人
readyList = jQuery.Deferred();
/**
W3C标准DOM浏览器
* 0-uninitialized:XML 对象被产生,但没有任何文件被加载。
* 1-loading:加载程序进行中,但文件尚未开始解析。
* 2-loaded:部分的文件已经加载且进行解析,但对象模型尚未生效。
* 3-interactive:仅对已加载的部分文件有效,在此情况下,对象模型是有效但只读的。
* 4-complete:文件已完全加载,代表加载成功。
*/ // 检测document内容是否加载完成,加载完成返回true,否者返回false
if (document.readyState === "complete") { /**
* 函数延迟0毫秒执行并不是立即执行, 而是等浏览器运行完挂起的事件句柄和已经更新完文档状态之后才
* 运行这个函数.详情见《JavaScript Definition Guide 5th Edition(JavaScript权威指南第5版)》
* 函数延迟1毫秒或者为空代表立即执行
*/
// 立即调用jQuery.ready方法,执行预加载内容
setTimeout(jQuery.ready); // 检测是否符合W3C标准事件模型(IE不支持)
} else if (document.addEventListener) {
// 监听DOMContentLoaded事件,当DOM加载完成,触发completed方法
// DOMContentLoaded事件在DOM加载完成时触发
// completed方法,目的是先删除监听DOMContentLoaded事件,然后执行jQuery.ready()方法。(删除事件,清除内存)
document.addEventListener("DOMContentLoaded", completed, false); // 若失败,给window.onload注册一个jQuery.ready方法,并在页面加载完成之后执行,目的是兼容低版本浏览器,防止出现预加载失败
window.addEventListener("load", completed, false); // IE事件模型
} else {
// 监听onreadystatechange事件,当DOM加载完成,触发DOMContentLoaded方法
document.attachEvent("onreadystatechange", completed); // 同理,若失败,兼容操作.
window.attachEvent("onload", completed); // 声明一个变量top, 目的:如果在IE下,文档不是嵌套在框架中, 就不断地检测文档是否准备就绪.
var top = false; try {
//检测是否嵌套在框架中,嵌套在框架中返回false,不嵌套返回document.documentElement
//返回嵌入当前window对象的元素(比如 <iframe> 或者 <object>),如果当前window对象已经是顶层窗口,则返回null,如果有框架则document.documentElement返回为null.
top = window.frameElement == null && document.documentElement;
} catch (e) { } // 检测是否存在doScroll方法
// IE支持doScroll,doScroll捕捉页面垂直和水平的滚动,他在ondocumentready 事件触发之后,onload事件触发之前触发
if (top && top.doScroll) {
(function doScrollCheck() {
if (!jQuery.isReady) { try {
top.doScroll("left");
} catch (e) {
return setTimeout(doScrollCheck, );
} detach(); // 执行jQuery.ready方法,说明页面DOM加载完成,其实就是改变deffered对象的状态,resolvewith完成,触发完成回调done(fn)
jQuery.ready();
}
})();
}
}
}
// 返回一个被限制的委托人(只能执行,不能改变的状态的委托人)
return readyList.promise(obj);
};

jQuery源码dom ready分析的更多相关文章

  1. jQuery源码-dom操作之jQuery.fn.html

    写在前面 前面陆陆续续写了jQuery源码的一些分析,尽可能地想要cover里面的源码细节,结果导致进度有些缓慢.jQuery的源码本来就比较晦涩,里面还有很多为了解决兼容问题很引入的神代码,如果不g ...

  2. jquery源码 DOM加载

    jQuery版本:2.0.3 DOM加载有关的扩展 isReady:DOM是否加载完(内部使用) readyWait:等待多少文件的计数器(内部使用) holdReady():推迟DOM触发 read ...

  3. jQuery源码 Ajax模块分析

    写在前面: 先讲讲ajax中的相关函数,然后结合函数功能来具体分析源代码. 相关函数: >>ajax全局事件处理程序 .ajaxStart(handler) 注册一个ajaxStart事件 ...

  4. jQuery源码解读-事件分析

    最原始的事件注册 addEventListener方法大家应该都很熟悉,它是Html元素注册事件最原始的方法.先看下addEventListener方法签名: element.addEventList ...

  5. jQuery源码-dom操作之jQuery.fn.text

    写在前面 jQuery.fn.text在jQuery是个使用频率比较高的接口,它的作用无非是设置/获取dom节点的内容文本,下文会通过几个简单的例子来说明.text()接口的使用,以及最后会对源码进行 ...

  6. jQuery源码分析学习--资料收集--更新中

    1.逐行分析jQuery源码的奥秘 - 网易云课堂  http://study.163.com/course/courseMain.htm?courseId=465001#/courseDetail? ...

  7. jQuery源码解析资源便签

    最近开始解读jQuery源码,下面的链接都是搜过来的,当然妙味课堂 有相关的一系列视频,长达100多期,就像一只蜗牛慢慢爬, 至少品读三个框架,以后可以打打怪,自己造造轮子. 完全理解jQuery源代 ...

  8. jquery源码分析(二)——架构设计

    要学习一个库首先的理清它整体架构: 1.jQuery源码大致架构如下:(基于 jQuery 1.11 版本,共计8829行源码)(21,94)                定义了一些变量和函数jQu ...

  9. jQuery源码分析系列

    声明:本文为原创文章,如需转载,请注明来源并保留原文链接Aaron,谢谢! 版本截止到2013.8.24 jQuery官方发布最新的的2.0.3为准 附上每一章的源码注释分析 :https://git ...

随机推荐

  1. Spring4.0+Hibernate4.0+Struts2.3整合包括增删改查案例,解决整合中出现的异常

    源码下载:http://download.csdn.net/detail/cmcc_1234/7034775 ======================Application.xml======== ...

  2. 在jybot下跑Selenium2Library

    应用场景:项目组要将原有SeleniumLibrary写的脚本切换到Selenium2Library(后称S2L)下,但是原来有很多Java写的库,综合考虑认为还是在Jython下跑比较合适.但是安装 ...

  3. Mes首检确认统计的存储过程

    USE [ChiefmesNEW]GO/****** Object: StoredProcedure [dbo].[st_MES_RptInspectFirstCollect] Script Date ...

  4. Http下的各种操作类.WebApi系列~通过HttpClient来调用Web Api接口

    1.WebApi系列~通过HttpClient来调用Web Api接口 http://www.cnblogs.com/lori/p/4045413.html HttpClient使用详解(java版本 ...

  5. Jdk和Jre目录和三个lib目录说明----外部扩展jar包servlet,mysql,oracle等

    以下文章转载自a personal blog:For Future,因为昨天下午在cmd模式下编译servlet失败,后来在网上找到这篇文章帮我解决了该问题,我觉得挺值得收藏的,并且这篇文章对&quo ...

  6. Qtwebkit flashplayer插件问题

      复制npswf32.dll 到 C:\WINDOWS\system32\Macromed\Flash\ 代码加入: //! [1] QNetworkProxyFactory::setUseSyst ...

  7. SCCM 2007 R2部署、操作详解系列之概念

    站点类型 在安装站点时,您决定它将是主站点还是辅助站点.然后,在安装其他站点时,您可以选择将其安排到层次结构关系中,以便父站点管理子站点,中央站点收集所有站点信息,从而进行集中式管理.也可以根据业务和 ...

  8. Android自定义图形,图形的拼接、叠加、相容

    直接上Xfermode子类: AvoidXfermode  指定了一个颜色和容差,强制Paint避免在它上面绘图(或者只在它上面绘图). PixelXorXfermode  当覆盖已有的颜色时,应用一 ...

  9. .NET连接SAP系统专题:SAP中新建可远程调用的RFC(二)

    何谓RFC,就是一个Function,可以被非SAP系统调用,比如VB,C#,Java等.如果我们在RFC中INCLUDE了相关的业务逻辑,那么我们就可以完全操控SAP中的业务数据了.就像在TTE里, ...

  10. C#调用Excel VBA宏

    近日的一系列工作是做网站的营运维护,因此做了大量的支持工具.有Excel中写VBA的,也有直接C#做的工具.有时需要在C#中执行Excel VBA宏,甚至有时还需要在执行了VBA宏之后,获取返回值再进 ...