protoype.js学习之Ajax对象(三)
1
/*
*
2 * Ajax类,getTransport类方法返回一个xmlhttp对象,注意这里就用到了Try.these
3 */
4 var Ajax = {
5 getTransport: function () {
6 return Try.these(
7 function () {
8 return new XMLHttpRequest()
9 },
10 function () {
11 return new ActiveXObject('Msxml2.XMLHTTP')
12 },
13 function () {
14 return new ActiveXObject('Microsoft.XMLHTTP')
15 }
16 ) || false ;
17 },
18
19 activeRequestCount: 0
20 }
21
22 Ajax.Responders = {
23 responders: [],
24
25 _each: function (iterator) {
26 this .responders._each(iterator);
27 },
28
29 register: function (responderToAdd) {
30 if ( ! this .include(responderToAdd))
31 this .responders.push(responderToAdd);
32 },
33
34 unregister: function (responderToRemove) {
35 this .responders = this .responders.without(responderToRemove);
36 },
37
38 dispatch: function (callback, request, transport, json) {
39 this .each( function (responder) {
40 if (responder[callback] && typeof responder[callback] == ' function ') {
41 try {
42 responder[callback].apply(responder, [request, transport, json]);
43 } catch (e) {
44 }
45 }
46 });
47 }
48 };
49
50 Object.extend(Ajax.Responders, Enumerable);
51
52 Ajax.Responders.register({
53 onCreate: function () {
54 Ajax.activeRequestCount ++ ;
55 },
56
57 onComplete: function () {
58 Ajax.activeRequestCount -- ;
59 }
60 });
61 /* *
62 * Ajax.Base 声明为一个基础对象类型,这里没有使用Class.create()方法,
63 * 因为Ajax.Base不需要实例化,只是作为基类,让子类来继承。
64 */
65 Ajax.Base = function () {
66 };
67 /* *
68 * Ajax.Base提供了一些Ajax.Request Ajax.PeriodicalUpdater共享的方法
69 * 这些方法被放在一个基类中,避免在Ajax.Request和Ajax.PeriodicalUpdater都实现。他们继承Ajax.Base
70 * The Ajax Object的options决定了怎样的Ajax Request执行,在Ajax Request初始化时,
71 * options首先设置默认属性,然后再extend参数对象,参数对象中有同名的属性,就覆盖默认的属性值
72 * 有一些属性是Ajax请求必须的,所以在Ajax.base对象中设置了默认值
73 *
74 */
75 Ajax.Base.prototype = {
76 setOptions: function (options) {
77 this .options = {
78 method: 'post',
79 asynchronous: true ,
80 contentType: 'application / x - www - form - urlencoded',
81 parameters: ''
82 }
83 Object.extend( this .options, options || {});
84 },
85 // 下面两个方法判断是否正常返回了响应
86 responseIsSuccess: function () {
87 return this .transport.status == undefined
88 || this .transport.status == 0
89 || ( this .transport.status >= 200 && this .transport.status < 300 );
90 },
91
92 responseIsFailure: function () {
93 return ! this .responseIsSuccess();
94 }
95 }
96 // Request对象,这回用了Class.create(),因为下面initialize初始化
97 Ajax.Request = Class.create();
98
99 // Events对象,对应XMLHttpRequest中的请求状态
100 // Uninitialized: 未初始化;Loading: 正在加载 ;Loaded:已加载;Interactive:交互中;Complete:完成
101
102 Ajax.Request.Events =
103 ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];
104
105 /* *
106 * Ajax.Request继承了Ajax.Base,并且添加了一个构造方法(initialize)
107 * initialize方法是必须的,因为Ajax请求属性继承Ajax.Base的后,至少还需要一个请求URL,才能工作。
108 * 有趣的是,初始化方法中调用了一个request的方法,所以请求被立刻执行,当Ajax.Request实例被初始化时。
109 */
110 Ajax.Request.prototype = Object.extend( new Ajax.Base(), {
111 initialize: function (url, options) {
112 this .transport = Ajax.getTransport();
113 this .setOptions(options); // 设置请求的的属性,调用Ajax.Base方法
114 this .request(url);
115 },
116
117 /* *
118 * 在Prototype中,一个Ajax.Request是一个到服务器的一个异步的请求,一个没有处理的response返回给调用者。
119 */
120 request: function (url) {
121 // 从Ajax.Base’s options对象中,获得请求参数字符串,如果this.options.parameters为空,请求参数被设空。
122 // 如果参数不为空,在请求参数后添加"&_=",应该是确保url的唯一性,避免浏览器缓存请求的结果。
123 var parameters = this .options.parameters || '';
124 if (parameters.length > 0 ) parameters += ' & _ = ';
125
126 /* Simulate other verbs over post */
127 if ( this .options.method != 'get' && this .options.method != 'post') {
128 parameters += (parameters.length > 0 ? ' & ' : '') + '_method = ' + this .options.method;
129 this .options.method = 'post';
130 }
131 // 下面请求将被发送,为了捕捉网络的异常,相关的代码被放到try块中
132 try {
133 this .url = url;
134 // 如果请求方法是get,参数将被连接到URL后
135 if ( this .options.method == 'get' && parameters.length > 0 )
136 this .url += ( this .url.match( / \ ?/ ) ? ' & ' : ' ? ') + parameters;
137
138 // onCreate事件被发给Responders对象,
139 // 请求开始 ,Ajax.Responders中注册onCreate的方法就会执行
140 Ajax.Responders.dispatch('onCreate', this , this .transport);
141
142 // XMLHttpRequest.open()方法,建立对服务器的调用。
143 this .transport.open( this .options.method, this .url,
144 this .options.asynchronous);
145
146 // 这里提供了XMLHttpRequest传输过程中每个步骤的回调函数
147 // 每10ms会调用一次这个方法,传的参数是Loading
148 if ( this .options.asynchronous)
149 setTimeout( function () {
150 this .respondToReadyState( 1 )
151 }.bind( this ), 10 );
152
153 // XMLHttpRequest状态改变时,onStateChange方法调用。
154 this .transport.onreadystatechange = this .onStateChange.bind( this );
155
156 // 设置request头
157 this .setRequestHeaders();
158
159 // 如果方法是post,参数被作为POST headers 被send()方法发送出去,否则,什么也不发送。
160 var body = this .options.postBody ? this .options.postBody : parameters;
161 this .transport.send( this .options.method == 'post' ? body : null );
162
163 /* Force Firefox to handle ready state 4 for synchronous requests */
164 if ( ! this .options.asynchronous && this .transport.overrideMimeType)
165 this .onStateChange();
166
167 } catch (e) {
168
169 this .dispatchException(e);
170 }
171 },
172
173 // 设置request头
174 setRequestHeaders: function () {
175 // 默认的请求头被建立,requestHeaders是个数组
176 var requestHeaders =
177 ['X - Requested - With', 'XMLHttpRequest',
178 'X - Prototype - Version', Prototype.Version,
179 'Accept', 'text / javascript, text / html, application / xml, text / xml, * /* '];
180 //如果请求用post方法,Content-type将被添加到请求头中
181 if (this.options.method == 'post') {
182 requestHeaders.push('Content-type', this.options.contentType);
183
184 /* Force "Connection: close" for Mozilla browsers to work around
185 * a bug where XMLHttpReqeuest sends an incorrect Content-length
186 * header. See Mozilla Bugzilla #246651.
187 */
188 if ( this .transport.overrideMimeType)
189 requestHeaders.push('Connection', 'close');
190 }
191 // 如果在request的options中有requestHeaders属性
192 // 它们将添加到requestHeaders
193 if ( this .options.requestHeaders)
194 requestHeaders.push.apply(requestHeaders, this .options.requestHeaders);
195
196 // requestHeaders中每一个key-value对,通过XMLhttpRequest的setRequestHeader方法设置请求实例的请求头属性中
197
198 for ( var i = 0 ; i < requestHeaders.length; i += 2 )
199 this .transport.setRequestHeader(requestHeaders[i], requestHeaders[i + 1 ]);
200 },
201 /* *
202 * 状态变化,并且readyState不是Loading时就调用回调函数。
203 */
204 onStateChange: function () {
205 var readyState = this .transport.readyState;
206 if (readyState != 1 )
207 this .respondToReadyState( this .transport.readyState);
208 },
209
210 // 根据name取得XMLHttpRequest中指定的HTTP头
211 header: function (name) {
212 try {
213 return this .transport.getResponseHeader(name);
214 } catch (e) {
215 }
216 },
217 // 执行HTTP头中'X-JSON'对应的内容
218 evalJSON: function () {
219 try {
220 return eval('(' + this .header('X - JSON') + ')');
221 } catch (e) {
222 }
223 },
224
225 /* *
226 * 执行包含在response text中的脚本,并返回结果
227 */
228 evalResponse: function () {
229 try {
230 return eval( this .transport.responseText);
231 } catch (e) {
232 this .dispatchException(e);
233 }
234 },
235
236 respondToReadyState: function (readyState) {
237 // readyState将被映射到Events定义得事件
238 var event = Ajax.Request.Events[readyState];
239 // 获取当前的XMLHttpRequest对象,执行HTTP头中'X-JSON'对应的内容
240 var transport = this .transport, json = this .evalJSON();
241 // 如果event == 'Complete',response响应被接受。
242 if (event == 'Complete') {
243 try { // 按优先级触发事件 如果处理函数不存在则执行emptyFunction忽略此事件
244 ( this .options['on' + this .transport.status]
245 || this .options['on' + ( this .responseIsSuccess() ? 'Success' : 'Failure')]
246 || Prototype.emptyFunction)(transport, json);
247 } catch (e) {
248 this .dispatchException(e);
249 }
250 // 如果响应的Content-type是 text/javascript,prototype将用evalResponse方法执行包含在请求的js代码
251 if (( this .header('Content - type') || '').match( /^ text\ / javascript / i))
252 this .evalResponse();
253 }
254 // XMLHttpRequest状态的变化,onLoaded, onInteractive, onComplete方法调用并传json对象
255 // 同时事件还发送给Responders对象
256 try {
257 ( this .options['on' + event] || Prototype.emptyFunction)(transport, json);
258 Ajax.Responders.dispatch('on' + event, this , transport, json);
259 } catch (e) {
260 this .dispatchException(e);
261 }
262
263 /* Avoid memory leak in MSIE: clean up the oncomplete event handler */
264 if (event == 'Complete')
265 this .transport.onreadystatechange = Prototype.emptyFunction;
266 },
267
268 dispatchException: function (exception) { // 处理异常,Prototype.emptyFunction为默认的处理方法
269 ( this .options.onException || Prototype.emptyFunction)( this , exception);
270 Ajax.Responders.dispatch('onException', this , exception);
271 }
272 });
273
274 /* *
275 * Ajax.Updater继承Ajax.Request,是一格Ajax.Request功能增强类。它执行和Ajax.Request同样的任务,
276 * 但是response不仅可以传递个onComplete处理,还可以响应后的HTML结果自动放到指定的container
277 */
278 Ajax.Updater = Class.create();
279
280 Object.extend(Object.extend(Ajax.Updater.prototype, Ajax.Request.prototype), {
281 // 初始化方法比Ajax.Request多了一个container参数,response
282 // 将被放置在container中
283 initialize: function (container, url, options) {
284 // success:请求响应成功时,接收response的容器对象
285 this .containers = {
286 success: container.success ? $(container.success) : $(container),
287 failure: container.failure ? $(container.failure) :
288 (container.success ? null : $(container))
289 }
290
291 this .transport = Ajax.getTransport();
292 this .setOptions(options);
293
294 var onComplete = this .options.onComplete || Prototype.emptyFunction;
295
296 // onComplete扩展包含一个对updateContent()方法的调用
297 this .options.onComplete = ( function (transport, object) {
298 this .updateContent();
299 onComplete(transport, object);
300 }).bind( this );
301
302 this .request(url);
303 },
304
305 updateContent: function () {
306 // 如果AJAX请求响应成功,则获取接收的容器对象,否则获取请求错误时的容器对象。
307 var receiver = this .responseIsSuccess() ?
308 this .containers.success : this .containers.failure;
309 var response = this .transport.responseText;
310
311 // 如果this.options.evalScripts为false,从response移出所有的JavaScript脚本
312 if ( ! this .options.evalScripts)
313 response = response.stripScripts();
314
315 // 如果接收对象存在
316 if (receiver) {
317 // 判断是将响应文本insertion还是update到receiver对象中
318 if ( this .options.insertion) {
319 new this .options.insertion(receiver, response);
320 } else {
321 Element.update(receiver, response);
322 }
323 }
324
325 if ( this .responseIsSuccess()) {
326 if ( this .onComplete)
327 setTimeout( this .onComplete.bind( this ), 10 );
328 }
329 }
330 });
331
332 /* *
333 * Ajax.PeriodicalUpdater对Ajax.Updater进行包装。对Ajax.Updater添加了一个定时器。
334 * 周期性的执行Ajax.Updater对象来更新DOM element
335 */
336 Ajax.PeriodicalUpdater = Class.create();
337 Ajax.PeriodicalUpdater.prototype = Object.extend( new Ajax.Base(), {
338 initialize: function (container, url, options) {
339 this .setOptions(options);
340 this .onComplete = this .options.onComplete;
341
342 this .frequency = ( this .options.frequency || 2 ); // 两次刷新之间的间隔
343 this .decay = ( this .options.decay || 1 ); // 重负执行任务的时候保持的衰败水平
344
345 this .updater = {};
346 this .container = container;
347 this .url = url;
348
349 this .start(); // 开始Ajax.Updater循环
350 },
351
352 start: function () {
353 // 使options的onComplete的指针指向当前的Ajax.PeriodicalUpdater对的updateComplete方法。
354 this .options.onComplete = this .updateComplete.bind( this );
355 this .onTimerEvent();
356 },
357
358 stop: function () {
359 this .updater.options.onComplete = undefined;
360 clearTimeout( this .timer);
361 ( this .onComplete || Prototype.emptyFunction).apply( this , arguments);
362 },
363
364 updateComplete: function (request) {
365 if ( this .options.decay) {
366 this .decay = (request.responseText == this .lastText ?
367 this .decay * this .options.decay : 1 );
368
369 this .lastText = request.responseText;
370 }
371 // 返回一个标志(timer)留作被stop函数调用, 以停止定时器
372 this .timer = setTimeout( this .onTimerEvent.bind( this ),
373 this .decay * this .frequency * 1000 );
374 },
375
376 onTimerEvent: function () {
377 this .updater = new Ajax.Updater( this .container, this .url, this .options);
378 }
379 });
2 * Ajax类,getTransport类方法返回一个xmlhttp对象,注意这里就用到了Try.these
3 */
4 var Ajax = {
5 getTransport: function () {
6 return Try.these(
7 function () {
8 return new XMLHttpRequest()
9 },
10 function () {
11 return new ActiveXObject('Msxml2.XMLHTTP')
12 },
13 function () {
14 return new ActiveXObject('Microsoft.XMLHTTP')
15 }
16 ) || false ;
17 },
18
19 activeRequestCount: 0
20 }
21
22 Ajax.Responders = {
23 responders: [],
24
25 _each: function (iterator) {
26 this .responders._each(iterator);
27 },
28
29 register: function (responderToAdd) {
30 if ( ! this .include(responderToAdd))
31 this .responders.push(responderToAdd);
32 },
33
34 unregister: function (responderToRemove) {
35 this .responders = this .responders.without(responderToRemove);
36 },
37
38 dispatch: function (callback, request, transport, json) {
39 this .each( function (responder) {
40 if (responder[callback] && typeof responder[callback] == ' function ') {
41 try {
42 responder[callback].apply(responder, [request, transport, json]);
43 } catch (e) {
44 }
45 }
46 });
47 }
48 };
49
50 Object.extend(Ajax.Responders, Enumerable);
51
52 Ajax.Responders.register({
53 onCreate: function () {
54 Ajax.activeRequestCount ++ ;
55 },
56
57 onComplete: function () {
58 Ajax.activeRequestCount -- ;
59 }
60 });
61 /* *
62 * Ajax.Base 声明为一个基础对象类型,这里没有使用Class.create()方法,
63 * 因为Ajax.Base不需要实例化,只是作为基类,让子类来继承。
64 */
65 Ajax.Base = function () {
66 };
67 /* *
68 * Ajax.Base提供了一些Ajax.Request Ajax.PeriodicalUpdater共享的方法
69 * 这些方法被放在一个基类中,避免在Ajax.Request和Ajax.PeriodicalUpdater都实现。他们继承Ajax.Base
70 * The Ajax Object的options决定了怎样的Ajax Request执行,在Ajax Request初始化时,
71 * options首先设置默认属性,然后再extend参数对象,参数对象中有同名的属性,就覆盖默认的属性值
72 * 有一些属性是Ajax请求必须的,所以在Ajax.base对象中设置了默认值
73 *
74 */
75 Ajax.Base.prototype = {
76 setOptions: function (options) {
77 this .options = {
78 method: 'post',
79 asynchronous: true ,
80 contentType: 'application / x - www - form - urlencoded',
81 parameters: ''
82 }
83 Object.extend( this .options, options || {});
84 },
85 // 下面两个方法判断是否正常返回了响应
86 responseIsSuccess: function () {
87 return this .transport.status == undefined
88 || this .transport.status == 0
89 || ( this .transport.status >= 200 && this .transport.status < 300 );
90 },
91
92 responseIsFailure: function () {
93 return ! this .responseIsSuccess();
94 }
95 }
96 // Request对象,这回用了Class.create(),因为下面initialize初始化
97 Ajax.Request = Class.create();
98
99 // Events对象,对应XMLHttpRequest中的请求状态
100 // Uninitialized: 未初始化;Loading: 正在加载 ;Loaded:已加载;Interactive:交互中;Complete:完成
101
102 Ajax.Request.Events =
103 ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];
104
105 /* *
106 * Ajax.Request继承了Ajax.Base,并且添加了一个构造方法(initialize)
107 * initialize方法是必须的,因为Ajax请求属性继承Ajax.Base的后,至少还需要一个请求URL,才能工作。
108 * 有趣的是,初始化方法中调用了一个request的方法,所以请求被立刻执行,当Ajax.Request实例被初始化时。
109 */
110 Ajax.Request.prototype = Object.extend( new Ajax.Base(), {
111 initialize: function (url, options) {
112 this .transport = Ajax.getTransport();
113 this .setOptions(options); // 设置请求的的属性,调用Ajax.Base方法
114 this .request(url);
115 },
116
117 /* *
118 * 在Prototype中,一个Ajax.Request是一个到服务器的一个异步的请求,一个没有处理的response返回给调用者。
119 */
120 request: function (url) {
121 // 从Ajax.Base’s options对象中,获得请求参数字符串,如果this.options.parameters为空,请求参数被设空。
122 // 如果参数不为空,在请求参数后添加"&_=",应该是确保url的唯一性,避免浏览器缓存请求的结果。
123 var parameters = this .options.parameters || '';
124 if (parameters.length > 0 ) parameters += ' & _ = ';
125
126 /* Simulate other verbs over post */
127 if ( this .options.method != 'get' && this .options.method != 'post') {
128 parameters += (parameters.length > 0 ? ' & ' : '') + '_method = ' + this .options.method;
129 this .options.method = 'post';
130 }
131 // 下面请求将被发送,为了捕捉网络的异常,相关的代码被放到try块中
132 try {
133 this .url = url;
134 // 如果请求方法是get,参数将被连接到URL后
135 if ( this .options.method == 'get' && parameters.length > 0 )
136 this .url += ( this .url.match( / \ ?/ ) ? ' & ' : ' ? ') + parameters;
137
138 // onCreate事件被发给Responders对象,
139 // 请求开始 ,Ajax.Responders中注册onCreate的方法就会执行
140 Ajax.Responders.dispatch('onCreate', this , this .transport);
141
142 // XMLHttpRequest.open()方法,建立对服务器的调用。
143 this .transport.open( this .options.method, this .url,
144 this .options.asynchronous);
145
146 // 这里提供了XMLHttpRequest传输过程中每个步骤的回调函数
147 // 每10ms会调用一次这个方法,传的参数是Loading
148 if ( this .options.asynchronous)
149 setTimeout( function () {
150 this .respondToReadyState( 1 )
151 }.bind( this ), 10 );
152
153 // XMLHttpRequest状态改变时,onStateChange方法调用。
154 this .transport.onreadystatechange = this .onStateChange.bind( this );
155
156 // 设置request头
157 this .setRequestHeaders();
158
159 // 如果方法是post,参数被作为POST headers 被send()方法发送出去,否则,什么也不发送。
160 var body = this .options.postBody ? this .options.postBody : parameters;
161 this .transport.send( this .options.method == 'post' ? body : null );
162
163 /* Force Firefox to handle ready state 4 for synchronous requests */
164 if ( ! this .options.asynchronous && this .transport.overrideMimeType)
165 this .onStateChange();
166
167 } catch (e) {
168
169 this .dispatchException(e);
170 }
171 },
172
173 // 设置request头
174 setRequestHeaders: function () {
175 // 默认的请求头被建立,requestHeaders是个数组
176 var requestHeaders =
177 ['X - Requested - With', 'XMLHttpRequest',
178 'X - Prototype - Version', Prototype.Version,
179 'Accept', 'text / javascript, text / html, application / xml, text / xml, * /* '];
180 //如果请求用post方法,Content-type将被添加到请求头中
181 if (this.options.method == 'post') {
182 requestHeaders.push('Content-type', this.options.contentType);
183
184 /* Force "Connection: close" for Mozilla browsers to work around
185 * a bug where XMLHttpReqeuest sends an incorrect Content-length
186 * header. See Mozilla Bugzilla #246651.
187 */
188 if ( this .transport.overrideMimeType)
189 requestHeaders.push('Connection', 'close');
190 }
191 // 如果在request的options中有requestHeaders属性
192 // 它们将添加到requestHeaders
193 if ( this .options.requestHeaders)
194 requestHeaders.push.apply(requestHeaders, this .options.requestHeaders);
195
196 // requestHeaders中每一个key-value对,通过XMLhttpRequest的setRequestHeader方法设置请求实例的请求头属性中
197
198 for ( var i = 0 ; i < requestHeaders.length; i += 2 )
199 this .transport.setRequestHeader(requestHeaders[i], requestHeaders[i + 1 ]);
200 },
201 /* *
202 * 状态变化,并且readyState不是Loading时就调用回调函数。
203 */
204 onStateChange: function () {
205 var readyState = this .transport.readyState;
206 if (readyState != 1 )
207 this .respondToReadyState( this .transport.readyState);
208 },
209
210 // 根据name取得XMLHttpRequest中指定的HTTP头
211 header: function (name) {
212 try {
213 return this .transport.getResponseHeader(name);
214 } catch (e) {
215 }
216 },
217 // 执行HTTP头中'X-JSON'对应的内容
218 evalJSON: function () {
219 try {
220 return eval('(' + this .header('X - JSON') + ')');
221 } catch (e) {
222 }
223 },
224
225 /* *
226 * 执行包含在response text中的脚本,并返回结果
227 */
228 evalResponse: function () {
229 try {
230 return eval( this .transport.responseText);
231 } catch (e) {
232 this .dispatchException(e);
233 }
234 },
235
236 respondToReadyState: function (readyState) {
237 // readyState将被映射到Events定义得事件
238 var event = Ajax.Request.Events[readyState];
239 // 获取当前的XMLHttpRequest对象,执行HTTP头中'X-JSON'对应的内容
240 var transport = this .transport, json = this .evalJSON();
241 // 如果event == 'Complete',response响应被接受。
242 if (event == 'Complete') {
243 try { // 按优先级触发事件 如果处理函数不存在则执行emptyFunction忽略此事件
244 ( this .options['on' + this .transport.status]
245 || this .options['on' + ( this .responseIsSuccess() ? 'Success' : 'Failure')]
246 || Prototype.emptyFunction)(transport, json);
247 } catch (e) {
248 this .dispatchException(e);
249 }
250 // 如果响应的Content-type是 text/javascript,prototype将用evalResponse方法执行包含在请求的js代码
251 if (( this .header('Content - type') || '').match( /^ text\ / javascript / i))
252 this .evalResponse();
253 }
254 // XMLHttpRequest状态的变化,onLoaded, onInteractive, onComplete方法调用并传json对象
255 // 同时事件还发送给Responders对象
256 try {
257 ( this .options['on' + event] || Prototype.emptyFunction)(transport, json);
258 Ajax.Responders.dispatch('on' + event, this , transport, json);
259 } catch (e) {
260 this .dispatchException(e);
261 }
262
263 /* Avoid memory leak in MSIE: clean up the oncomplete event handler */
264 if (event == 'Complete')
265 this .transport.onreadystatechange = Prototype.emptyFunction;
266 },
267
268 dispatchException: function (exception) { // 处理异常,Prototype.emptyFunction为默认的处理方法
269 ( this .options.onException || Prototype.emptyFunction)( this , exception);
270 Ajax.Responders.dispatch('onException', this , exception);
271 }
272 });
273
274 /* *
275 * Ajax.Updater继承Ajax.Request,是一格Ajax.Request功能增强类。它执行和Ajax.Request同样的任务,
276 * 但是response不仅可以传递个onComplete处理,还可以响应后的HTML结果自动放到指定的container
277 */
278 Ajax.Updater = Class.create();
279
280 Object.extend(Object.extend(Ajax.Updater.prototype, Ajax.Request.prototype), {
281 // 初始化方法比Ajax.Request多了一个container参数,response
282 // 将被放置在container中
283 initialize: function (container, url, options) {
284 // success:请求响应成功时,接收response的容器对象
285 this .containers = {
286 success: container.success ? $(container.success) : $(container),
287 failure: container.failure ? $(container.failure) :
288 (container.success ? null : $(container))
289 }
290
291 this .transport = Ajax.getTransport();
292 this .setOptions(options);
293
294 var onComplete = this .options.onComplete || Prototype.emptyFunction;
295
296 // onComplete扩展包含一个对updateContent()方法的调用
297 this .options.onComplete = ( function (transport, object) {
298 this .updateContent();
299 onComplete(transport, object);
300 }).bind( this );
301
302 this .request(url);
303 },
304
305 updateContent: function () {
306 // 如果AJAX请求响应成功,则获取接收的容器对象,否则获取请求错误时的容器对象。
307 var receiver = this .responseIsSuccess() ?
308 this .containers.success : this .containers.failure;
309 var response = this .transport.responseText;
310
311 // 如果this.options.evalScripts为false,从response移出所有的JavaScript脚本
312 if ( ! this .options.evalScripts)
313 response = response.stripScripts();
314
315 // 如果接收对象存在
316 if (receiver) {
317 // 判断是将响应文本insertion还是update到receiver对象中
318 if ( this .options.insertion) {
319 new this .options.insertion(receiver, response);
320 } else {
321 Element.update(receiver, response);
322 }
323 }
324
325 if ( this .responseIsSuccess()) {
326 if ( this .onComplete)
327 setTimeout( this .onComplete.bind( this ), 10 );
328 }
329 }
330 });
331
332 /* *
333 * Ajax.PeriodicalUpdater对Ajax.Updater进行包装。对Ajax.Updater添加了一个定时器。
334 * 周期性的执行Ajax.Updater对象来更新DOM element
335 */
336 Ajax.PeriodicalUpdater = Class.create();
337 Ajax.PeriodicalUpdater.prototype = Object.extend( new Ajax.Base(), {
338 initialize: function (container, url, options) {
339 this .setOptions(options);
340 this .onComplete = this .options.onComplete;
341
342 this .frequency = ( this .options.frequency || 2 ); // 两次刷新之间的间隔
343 this .decay = ( this .options.decay || 1 ); // 重负执行任务的时候保持的衰败水平
344
345 this .updater = {};
346 this .container = container;
347 this .url = url;
348
349 this .start(); // 开始Ajax.Updater循环
350 },
351
352 start: function () {
353 // 使options的onComplete的指针指向当前的Ajax.PeriodicalUpdater对的updateComplete方法。
354 this .options.onComplete = this .updateComplete.bind( this );
355 this .onTimerEvent();
356 },
357
358 stop: function () {
359 this .updater.options.onComplete = undefined;
360 clearTimeout( this .timer);
361 ( this .onComplete || Prototype.emptyFunction).apply( this , arguments);
362 },
363
364 updateComplete: function (request) {
365 if ( this .options.decay) {
366 this .decay = (request.responseText == this .lastText ?
367 this .decay * this .options.decay : 1 );
368
369 this .lastText = request.responseText;
370 }
371 // 返回一个标志(timer)留作被stop函数调用, 以停止定时器
372 this .timer = setTimeout( this .onTimerEvent.bind( this ),
373 this .decay * this .frequency * 1000 );
374 },
375
376 onTimerEvent: function () {
377 this .updater = new Ajax.Updater( this .container, this .url, this .options);
378 }
379 });