/
jquery-ajax.txt
382 lines (257 loc) · 12.3 KB
/
jquery-ajax.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
ajax 在 1.5 由 Julian Aubourg 重写
细节: http://oksoclap.com/p/6Y26bm1ZsB
======================================= ajax.js =======================================
变量:
ajaxLocParts
ajax_nonce 当前时间
ajax_rquery = /\?/ 地址中的搜索起始处
rhash = /#.*$/
rts = /([?&])_=[^&]*/ 看来下划线在链接中有特殊用途
rheaders = /^(.*?):[ \t]*([^\r\n]*)\r?$/mg IE leaves an \r character at EOL
// #7653, #8125, #8152: local protocol detection
rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/
rnoContent = /^(?:GET|HEAD)$/ 没有响应体
rprotocol = /^\/\// 协议名
rurl = /^([\w.+-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/ 匹配 url 的协议、域名、端口号
_load = jQuery.fn.load 保留旧方法的引用??
prefilters
transports
allTypes = "*/".concat("*")
ajaxLocation 设置为当前页面的地址,根据 #8138,某些机器上的 IE 6-8 在设置了 document.domain 后,访问 location.protocal 会抛出异常。
一个 hack 方法是创建一个 a 标签,手动设置它的 href 为空,IE 会自动使用当前地址为其设置 href
测试结果发现在 chrome 和 IE 下均有效。
ajaxExtend:
#9887
ajax 的 extend 使用了深拷贝,但是有些属性使用深拷贝浪费内存,例如 context,所以该方法会跳过 ajaxSettings.flatOptions 中的属性
addToPrefiltersOrTransports:
向 prefilters 和 transports 两个对象中添加属性,属性名是 ajax 的 dataType,值是处理函数
如果第一个参数不是字符串,则 dataTypeExpression 为 "*"
dataType 前有 + 号表示该过滤条件要提前执行,使用 unshift 插入数组中。
inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ):
不知道在检查神马。
在函数调用中,例如 each,如果不需要使用排在前面的参数,但是这些参数又必须声明,那么可以使用 _ 作为占位符。
扩展 jQuery:
active
lastModified
etag
ajaxSettings 默认 ajax 参数
url: ajaxLocation,
type: "GET",
isLocal: rlocalProtocol.test( ajaxLocParts[ 1 ] ),
global: true,
processData: true,
async: true,
contentType: "application/x-www-form-urlencoded; charset=UTF-8",
accepts: {
"*": allTypes,
text: "text/plain",
html: "text/html",
xml: "application/xml, text/xml",
json: "application/json, text/javascript"
},
contents: {
xml: /xml/,
html: /html/,
json: /json/
},
responseFields: {
xml: "responseXML",
text: "responseText",
json: "responseJSON"
},
// Data converters
// Keys separate source (or catchall "*") and destination types with a single space
converters: {
// Convert anything to text
"* text": String,
// Text to html (true = no transformation)
"text html": true,
// Evaluate text as a json expression
"text json": jQuery.parseJSON,
// Parse text as xml
"text xml": jQuery.parseXML
},
// For options that shouldn't be deep extended:
// you can add your own custom options here if
// and when you create one that shouldn't be
// deep extended (see ajaxExtend)
flatOptions: {
url: true,
context: true
}
ajaxSetup
使用 ajaxExtend 扩展 jQuery.ajaxSettings,因为该方法会影响所有 ajax 请求,可能会对插件造成无法预期的后果,所以已经不推荐使用该方法了
ajaxPrefilter
发送 ajax 前处理 ajax 选项
使用 addToPrefiltersOrTransports
ajaxTransport
使用 addToPrefiltersOrTransports
ajax( url, options ):
主要方法!
流程:
处理参数列表,兼容 1.5 之前的版本
定义变量
获得最终的 option
处理 url
处理 type
设置 dataTypes
设置 crossDomain
inspectPrefiltersOrTransports( prefilters, s, options, jqXHR )
在上一步过程中, state 被修改为 2,表示 abort, 返回 jqXHR
(如果可能)触发 ajaxStart
通过 type 判断请求是否含有 content,如果没有,则
如果有 data,拼接到 url 后。
如果 cache 为 false,在 url 后增加 _ 参数。
检查 ifModified
设置 contentType
设置 accepts
循环 headers,设置对应的请求头
如果设置了 beforeSend,执行,判断返回值是否为 false 或 state 是否为 2,如果是,则调用 abort()
为 jqXHR 添加 success、 error、 complete 函数
transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );
若 transport 不存在,则
done( -1, "No Transport" );
否则,
jqXHR.readyState = 1;
触发 ajaxSend
如果此次请求为异步,并设置了 timeout,则
设置定时器,超时后执行 jqXHR.abort("timeout");
调用 transport.send( requestHeaders, done ),如果抛出异常
检测 state,
若 state < 2,表明请求未完成,调用 done( -1, e )
否则抛出异常
done( status, nativeStatusText, responses, headers ):
ajax 请求的回调函数。
如果 state 为 2, 返回
state = 2
清除 timeout 的定时(如果存在的话)
transport = undefined 垃圾回收
设置 jqXHR.readyState
判断请求是否成功
isSuccess = status >= 200 && status < 300 || status === 304
如果有响应值,则
调用 ajaxHandleResponses( s, jqXHR, responses )
使用 ajaxConvert 转换响应值
如果 isSuccess 为 true,则
如果设置了 ifModified,那么
修改 jQuery.lastModified 和 jQuery.etag
status 204 为 nocontent
304 为 notmodified
否则
设置 error
设置 jqXHR 的 status 和 statusText
如果 isSuccess 为 true,则
deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] )
否则
deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] )
根据 status 调用 statusCode
触发 ajaxSuccess 或 ajaxError 事件。
调用 completeDeferred
触发 ajaxComplete 事件
若所有请求都已结束,触发 ajaxStop 事件
返回 jqXHR
getScript:
jQuery.get( url, undefined, callback, "script" );
getJSON:
jQuery.get( url, data, callback, "json" );
jQuery.fn.load:
"ajaxStart", "ajaxStop", "ajaxComplete", "ajaxError", "ajaxSuccess", "ajaxSend":
添加对应的事件处理函数
jQuery.get
jQuery.post ( url, data, callback, type ),内部调用 jQuery.ajax
ajaxHandleResponses:
设置 jqXHR 的 responseXXX 属性
检测 content-type
检测 dataType
ajaxConvert
transport 被单独提取了出来,该对象提供了 send 和 abort 两个 api。
应该是为了解耦和。
======================================= ajax/xhr.js =======================================
#5280, IE 7 关闭窗口后还会保留 ajax 连接,只能重启浏览器。
解决办法是在 window 的 unload 事件中 abort 这些请求
xhrCallbacks 用于保存激活的 xhr 回调,便于在 unload 事件中调用 abort
createStandardXHR():
创建 XMLHttpRequest
createActiveXHR():
创建 ActiveXObject("Microsoft.XMLHTTP")
设置 ajaxSettings.xhr
IE 7 的 XMLHttpRequest 实现不完整,无法请求本地文件
检测是否支持 cros: xhr 对象是否有 withCredentials 属性
send :
创建 xhr
xhr.open()
xhrFields 用于为 xhr 增加自定义属性
如果 xhr 的 overrideMimeType 存在,覆盖 mime-type
设置 headers,这里要 try catch 的原因是 firefox 3 下的跨域访问
xhr.send() 会判断下是否有 content
定义 callback( _, isAbort ):
http://helpful.knobs-dials.com/index.php/Component_returned_failure_code:_0x80040111_(NS_ERROR_NOT_AVAILABLE)
firefox 中,出现网络错误后,访问 xhr 的属性会抛异常
callback 只会调用一次
if( callback && ... ) {
callback = undefined;
...
}
从 xhrCallbacks 中清除掉已经不活动的 xhr
如果是 abort 的,那么
调用 xhr.abort();
否则
设置 responses
IE 6-9 下,如果相应内容是二进制,那么访问 xhr.responseText 会报错
firefox 下,如果在错误的跨域请求下,访问 xhr.statusText 报错
IE 下,有时 status 会返回 1223 而不是 204
如果 responses 存在,调用 complete( status, statusText, responses, responseHeaders )
如果是同步请求,直接执行 callback
或,
IE 6 或 7 中,如果存在缓存并直接读取的话,xhr.readyState 为 4,那么运行 callback
或
如果 xhrOnUnloadAbort 存在,那么绑定 unload 事件
xhr.onreadystatechange = callback
abort:
callback 的第二个参数表示是否为 abort
if ( callback ) {
callback( undefined, true );
}
======================================= ajax/script.js =======================================
前面是个使用 ajaxSetup 和 ajaxPrefilter 的例子
在 filter 中
如果 cache 不存在
cache 为 false
如果 crossDomain 为 true
type 为 GET
global 为 false
ajaxTransport 中增加 script:
该 transport 只处理跨域访问
send( _, callback ):
创建 script 元素
script.async = true;
设置 script 的 charset ( 如果设置了 scriptCharset 的 option )
script.src = s.url;
设置 script.onload = script.onreadystatechange:
script.onload = script.onreadystatechange = null; 防止 IE 下内存泄露
移除 script 元素
script = null;
如果不是 abort, callback( 200, "success" );
#2709 和 #4378
绕过了 IE 6 下 base 元素的 bug
head.insertBefore( script, head.firstChild );
abort:
======================================= ajax/jsonp.js =======================================
jsonp 的 callback 由 jQuery.expando + "_" + ( ajax_nonce++ ) 组成
也可以从 oldCallbacks 里获得。
对于 jsonp 的处理是在 prefilter 中完成的,它拦截了 type 为 json 或 jsonp 的情况:
jsonProp: 首先检测 url 中是否有名为 ? 的属性名,如果没有再检查 data 中是否有
jsonp 的回调名可以通过 jsonpCallback 的 option 设置,它可以是字符串,也可以是函数,默认使用前面定义的 jsonpCallback 函数来确定
向 url 中插入回调函数名
设置 data-type 为 json
使用 overwritten 保存 window[ callbackName ], 将 callbackName 定义为新的全局函数,
使用 jqXHR 的 always 设置清除方法:
还原 window[ callbackName ]
如果 s[ callbackName ] 存在,表明该 callbackName 需要重复使用:
还原 s.jsonpCallback
将 callbackName 传入 oldCallbacks 中
jsop 请求成功后, window[ callbackName ] 执行, responseContainer 被设置
如果 responseContainer 存在,并且 overwritten 存在
执行 overwritten( responseContainer[0] )
这里 overwritten 存在应该是指用户自定义的函数
responseContainer = overwritten = undefined;