ready是在页面的DOM元素加载完成后执行回调函数(确切地说应该是回调函数列表)的方法,ready方法可多次被调用,传入的回调函数(单个或多个)将逐一放入回调函数列表readyList中,当ready事件(当然DOM事件中是没有所谓的ready事件的,这里只是为了解释自己起的)触发后,将逐一执行readyList中的回调函数
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 //.....代码省略