一、前言

  在平时开发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

 //构造函数,定义一个局部变量的jQueryjQuery =function (selector, context) {//jQuery对象实际上是init的构造函数的引用return newjQuery.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)returnrootjQuery.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:1,/**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) {returnsetTimeout(jQuery.ready);}//开关,记录DOM加载完成jQuery.isReady = true;//检测所有的观察者是否执行完成if (wait !== true && --jQuery.readyWait > 0) {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方法returnrootjQuery.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相关部分源码详细如下:

 //构造函数,定义一个局部变量的jQueryjQuery =function (selector, context) {//jQuery对象实际上是init的构造函数的引用return newjQuery.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方法returnrootjQuery.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:1,/**锁定或释放预加载委托人* @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 readyif (wait === true ? --jQuery.readyWait : jQuery.isReady) {return;}//检测body是否存在(IE的一个bug),存在继续向下执行,不存在进入语句,执行setTimeout定时器,直到body存在if (!document.body) {returnsetTimeout(jQuery.ready);}//开关,记录DOM加载完成jQuery.isReady = true;//检测所有的观察者是否执行完成if (wait !== true && --jQuery.readyWait > 0) {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,否者返回falseif (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, 50);}detach();//执行jQuery.ready方法,说明页面DOM加载完成,其实就是改变deffered对象的状态,resolvewith完成,触发完成回调done(fn)
jQuery.ready();}})();}}}//返回一个被限制的委托人(只能执行,不能改变的状态的委托人)returnreadyList.promise(obj);};

jQuery源码dom ready分析相关推荐

  1. jquery源码 DOM加载

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

  2. jQuery源码 Ajax模块分析

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

  3. 妙味课堂:一起学习jQuery源码【逐行分析jQuery源码的奥秘】(妙味课堂笔记)-- 框架接口(1-3)

    jQuery 的学习版本为: 2.0.3 匿名函数 匿名函数自执行,目的是防止变量污染 (function(window,undefined){})(window); 内层代码块分析 (functio ...

  4. JQuery 源码解析资料

    2019独角兽企业重金招聘Python工程师标准>>> jQuery源码分析系列目录 jQuery源码解读-理解架构 jQuery源码解析(架构与依赖模块) jQuery v1.10 ...

  5. jQuery源码分析-10事件处理-Event-事件绑定与删除-bind/unbind+live/die+delegat/unde

    10.4    .bind() .one() 10.4.1  如何使用 .bind( eventType, [eventData], handler(eventObject) )   在匹配的元素上绑 ...

  6. jQuery源码分析-10事件处理-Event-事件绑定与删除-bind/unbind+live/die+delegat/undelegate

    Js代码   作者:nuysoft/高云 QQ:47214707 EMail:nuysoft@gmail.com 声明:本文为原创文章,如需转载,请注明来源并保留原文链接. 后文预告:封装事件对象 便 ...

  7. jQuery源码分析系列

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

  8. [转]jQuery源码分析系列

    文章转自:jQuery源码分析系列-Aaron 版本截止到2013.8.24 jQuery官方发布最新的的2.0.3为准 附上每一章的源码注释分析 :https://github.com/JsAaro ...

  9. jQuery源码分析(二)——Sizzle

    在这一章中我们将重点分析jquery的选择器引擎.jquery在3.4版本后,将选择器引擎抽取出来单独放到了Sizzle.js 文件中,本文将基于这个版本来进行分析. 创建缓存 // line 40 ...

最新文章

  1. java表达式类型自动提升
  2. Orace 11g 监听 配置修改 说明
  3. go hive skynet_云风的skynet在国内外来看究竟算什么水平?可以一统国内游戏服务端框架吗?...
  4. Python random 模块 - Python零基础入门教程
  5. Gartner:人工智能将把部分专业工作变成公用事业
  6. ROS笔记(9) launch文件
  7. CESIUM加载glb的模型
  8. Tomcat服务器时间不正确
  9. 油猴脚本管理器的超详细下载安装使用教程—— 个性化浏览器
  10. vue 项目登录注册中如何使用滑块去校验
  11. 生物信息数据格式:fastq格式
  12. 省一级计算机操作题,江苏省计算机一级操作题大全
  13. 微信诈骗产业链,俩字儿是核心:杀熟
  14. macbook 微信双开命令
  15. swf 格式Flash 动画播放器在Android上的实现
  16. clipboard.js 实现动态获取内容并复制到剪切板
  17. ArcGIS简单的三维演示
  18. 汉明码(计算机组成原理)没听课也能懂
  19. WebRTC的拥塞控制技术(Congestion Control
  20. Java的就业主要的三个方向你知道吗

热门文章

  1. mac terminal常用命令接触
  2. 基于NopCommerce的开源电商系统改造总结
  3. 邓俊辉数据结构学习-3-栈
  4. 编程之美计算0到N中包含数字1的个数
  5. 【小白的CFD之旅】14 实例反思
  6. 类的大小,虚函数,继承
  7. 商品搜索引擎---推荐系统设计
  8. Android安全开发之安全使用HTTPS
  9. git server安装
  10. break 与 continue