jQuery源码分析之ready方法

  1 var //......代码省略
  2        //事件回调函数列表对象
  3         //为了便于解释暂且称之为ready事件回调函数列表对象,
  4         //当然DOM事件模型是没有所谓的ready事件的哦。
  5         readyList
  6         //......代码省略
  7  ;
  8 jQuery.fn = jQuery.prototype = {
  9     //......代码省略
 10     ready: function( fn ) {
 11         // Attach the listeners
 12         // 绑定ready事件监听器,DOM标准里是无所谓ready事件,
 13         // 这里只是自己起的为了方便分析代码
 14         jQuery.bindReady();
 15         // Add the callback
 16         // 添加回调函数到回调函数列表中
 17         readyList.add( fn );
 18         return this;
 19     },
 20     //......代码省略
 21 };
 22 jQuery.extend({
 23     //......代码省略
 24     // Is the DOM ready to be used? Set to true once it occurs.
 25     // 标识页面DOM元素是否已加载完毕
 26     isReady: false,
 27     // A counter to track how many items to wait for before
 28     // the ready event fires. See #6781
 29     readyWait: 1,
 30     // Hold (or release) the ready event
 31     holdReady: function( hold ) {
 32         if ( hold ) {
 33             jQuery.readyWait++;
 34         } else {
 35             jQuery.ready( true );
 36         }
 37     },
 38     // Handle when the DOM is ready
 39     ready: function( wait ) {
 40         // Either a released hold or an DOMready/load event and not yet ready
 41         if ( (wait === true && !--jQuery.readyWait) || (wait !== true && !jQuery.isReady) ) {
 42             // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
 43             if ( !document.body ) {
 44                 return setTimeout( jQuery.ready, 1 );
 45             }
 46             // Remember that the DOM is ready
 47             jQuery.isReady = true;
 48             // If a normal DOM Ready event fired, decrement, and wait if need be
 49             if ( wait !== true && --jQuery.readyWait > 0 ) {
 50                 return;
 51             }
 52             // If there are functions bound, to execute
 53             readyList.fireWith( document, [ jQuery ] );
 54             // Trigger any bound ready events
 55             if ( jQuery.fn.trigger ) {
 56                 jQuery( document ).trigger( "ready" ).off( "ready" );
 57             }
 58         }
 59     },
 60     bindReady: function() {
 61         //判断ready事件回调函数列表是否已初始化
 62         if ( readyList ) {
 63             //如是则返回
 64             return;
 65         }
 66         //创建ready事件回调函数列表对象
 67         //这里调用jQuery.Callbacks方法,
 68         //Callbacks的作用在上篇已说过,不再赘述
 69         readyList = jQuery.Callbacks( "once memory" );
 70         // Catch cases where $(document).ready() is called after the
 71         // browser event has already occurred.
 72         // 判断页面DOM元素是否已加载完毕
 73         if ( document.readyState === "complete" ) {
 74             // Handle it asynchronously to allow scripts the opportunity to delay ready
 75             // 如是则异步执行jQuery.ready方法
 76             // 调用setTimeout目的是异步执行jQuery.ready方法
 77             return setTimeout( jQuery.ready, 1 );
 78         }
 79         // Mozilla, Opera and webkit nightlies currently support this event
 80         // 支持W3C DOM标准的浏览器则用addEventListener绑定
 81         if ( document.addEventListener ) {
 82             // Use the handy event callback
 83             // 支持W3C DOM标准的浏览器一般是支持DOMContentLoaded事件
 84             // DOMContentLoaded是页面的DOM元素(仅仅只是DOM元素)全部加载完毕后触发
 85             document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false );
 86             // A fallback to window.onload, that will always work
 87             // 当然有些所谓支持W3C DOM标准的浏览器可能不支持DOMContentLoaded事件,
 88             // 为了不被坑爹,在此得留一手,为确保万无一失,再绑定window的load事件,
 89             // 因为window的load事件是所有浏览器都支持的,页面载入完成后是肯定会触发。
 90             // 在这里说明一下DOMContentLoaded和load事件的区别:
 91             // DOMContentLoaded事件是只要页面DOM元素全部加载完毕即触发
 92             // window的load事件是页面的所有DOM元素以及全部资源(如图片/flash)加载完毕即触发
 93             // 理论上,DOMContentLoaded要比window的load事件先触发
 94             window.addEventListener( "load", jQuery.ready, false );
 95         } 
 96         // If IE event model is used
 97         // 针对IE浏览器用attachEvent绑定事件
 98         // 题外话:IE遵循自己的一套DOM事件模型,与W3C DOM事件模型有很大不同
 99         // 故需特殊对待
100         else if ( document.attachEvent ) {
101             // ensure firing before onload,
102             // maybe late but safe also for iframes
103             // IE不支持DOMContentLoaded事件,但可使用onreadystatechange事件替代之
104             document.attachEvent( "onreadystatechange", DOMContentLoaded );
105             // A fallback to window.onload, that will always work
106             // 为了避免被onreadystatechange事件坑爹,需留一手,
107             // 绑定window的onload事件,这是页面载入完成后一定会触发的。
108             window.attachEvent( "onload", jQuery.ready );
109             // If IE and not a frame
110             // continually check to see if the document is ready
111             var toplevel = false;
112             try {
113                 //使用window.frameElement判断是否是顶级页面
114                 toplevel = window.frameElement == null;
115             } catch(e) {
116                 //抛异常,则当做不是顶级页面处理
117             }
118             //document.documentElement.doScroll
119             //IE独有方法,模拟用户滚动条点击;
120             //用此法判断IE下的DOM元素是否加载完成
121             if ( document.documentElement.doScroll && toplevel ) {
122                 doScrollCheck();
123             }
124         }
125     }
126 //......代码省略
127 });
128 //.....代码省略
129 // The DOM ready check for Internet Explorer
130 // 检测IE浏览器下的DOM元素是否加载完成
131 function doScrollCheck() {
132     //判断页面是否已加载完毕
133     //如是则无需再执行下面的检测代码
134     if ( jQuery.isReady ) {
135         return;
136     }
137     // 执行document.documentElement.doScroll方法
138     // 若抛异常,表示IE的DOM元素未加载完毕,则继续异步执行doScrollCheck检测
139     // 若不抛异常,表示IE的DOM元素加载完成,则将执行jQuery.ready方法
140     try {
141         // If IE is used, use the trick by Diego Perini
142         // http://javascript.nwbox.com/IEContentLoaded/
143         document.documentElement.doScroll("left");
144     } catch(e) {
145         setTimeout( doScrollCheck, 1 );
146         return;
147     }
148     // and execute any waiting functions
149     // IE的DOM元素加载完成调用jQuery.ready方法
150     jQuery.ready();
151 }
152 //.....代码省略
153 // Cleanup functions for the document ready method
154 //支持W3C DOM标准浏览器
155 if ( document.addEventListener ) {
156     //DOMContentLoaded事件回调函数实现
157   DOMContentLoaded = function() {
158        //移除DOMContentLoaded事件绑定
159     document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false );
160     jQuery.ready();
161   };
162 } 
163 //支持微软DOM标准浏览器
164 else if ( document.attachEvent ) {
165     //onreadystatechange事件回调函数实现
166   DOMContentLoaded = function() {
167     // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
168     if ( document.readyState === "complete" ) {
169             //移除onreadystatechange事件绑定
170        document.detachEvent( "onreadystatechange", DOMContentLoaded );
171         jQuery.ready();
172     }
173   };
174 }
175 //.....代码省略
原文地址:https://www.cnblogs.com/bender/p/3361146.html