ajax模块-zepto源码

前言

zepto是一个轻量级的类jQuery的JavaScript库,适合在移动端页面开发使用。轻量又提供许多dom操作API。

前面我们讲解了zepto模块和event模块,现在来看看ajax模块。

ajax模块

整体架构:
image

$.ajax()

$.ajax()是整个模块的核心,模块的其他函数方法一定程度都依赖于这个函数。

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
$.ajax = function(options){
* 将默认ajaxsetting和所传参数结合
* ajaxStart() 触发绑定的监听事件ajaxStart
* if (!settings.crossDomain) {
如果crossDomain设置为false,再次检查是否同域请求
}
* if (!settings.url){
如果为设置url,settings.url = window.location.toString()
}
* if ((hashIndex = settings.url.indexOf('#')) > -1){
如果url中存在#hash,去除#后的内容
}
* hasPlaceholder = /\?.+=\?/.test(settings.url)
if (hasPlaceholder) dataType = 'jsonp'{
匹配?后的参数,dataType设为jsonp
}
* if (settings.cache === false || (
(!options || options.cache !== true) &&
('script' == dataType || 'jsonp' == dataType)
)){
如果缓存为false,或者请求数据为'script'或'jsonp'
settings.url = appendQuery(settings.url, '_=' + Date.now())
}
* if ('jsonp' == dataType) {
if (!hasPlaceholder){
如果确定为jsonp,调用$.ajaxJSONP()
}
}
* 设置请求头信息
setHeader = function(name, value) { headers[name.toLowerCase()] = [name, value] }
setHeader('X-Requested-With', 'XMLHttpRequest')
setHeader('Accept', mime )
xhr.overrideMimeType && xhr.overrideMimeType(mime)
// overrideMimeType:重写由服务器返回的MIME type
setHeader('Content-Type', settings.contentType || 'application/x-www-form-urlencoded')
setHeader(name, settings.headers[name])

* xhr.onreadystatechange = function(){
// 注册监听xhr状态事件
if(){
ajaxSuccess():ajax执行成功回调
}else{
ajaxError() :ajax执行失败回调
}
}
* if (ajaxBeforeSend(xhr, settings) === false) {
执行ajaxBeforeSend(),
如果返回false,ajaxError()并终止xhr异步请求
}
* 检查是否异步请求,xhr.open()连接请求
var async = 'async' in settings ? settings.async : true
xhr.open(settings.type, settings.url, async, settings.username, settings.password)
* if (settings.xhrFields){
将xhrFields对象上的属性一一复制到xhr对象上。
}
* 调用原生setRequestHeader,将需要添加的请求头信息一一添加
for (name in headers) nativeSetHeader.apply(xhr, headers[name])
* if (settings.timeout > 0) {
如果存在timeout超时设置,声明一个abortTimeout回调函数,在请求超时的时候调用。
}
}

$.ajaxJSONP

一个包含Ajax请求的默认设置的对象。大部分的设置在 $.ajax中已经描述。以下设置为全局非常有用:

  • timeout (默认: 0):对Ajax请求设置一个非零的值指定一个默认的超时时间,以毫秒为单位。
  • global (默认: true):设置为false。以防止触发Ajax事件。
  • xhr (默认:XMLHttpRequest factory):设置为一个函数,它返回XMLHttpRequest实例(或一个兼容的对象)
  • accepts: 从服务器请求的MIME类型,指定dataType值:
    • script: “text/javascript, application/javascript”
    • json: “application/json”
    • xml: “application/xml, text/xml”
    • html: “text/html”
    • text: “text/plain
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$.ajaxJSONP = function(options, deferred){
* 获取jsonp函数引用
var _callbackName = options.jsonpCallback,
* 创建script节点,声明并给变量xhr,abort赋值
* $(script).on('load error', function(e, errorType){
* 监听load和error事件,
* 如果出现error,调用ajaxError;否则调用ajaxSuccess
* 执行jsonp函数
originalCallback(responseData[0])
})

* 设置script的src,并插入文档中
script.src = options.url.replace(/\?(.+)=\?/, '?$1=' + callbackName)
document.head.appendChild(script)
* 超时处理
}

$.param()

序列化一个对象,在Ajax请求中提交的数据使用URL编码的查询字符串表示形式。如果shallow设置为true。嵌套对象不会被序列化,嵌套数组的值不会使用放括号在他们的key上。

如果任何对象的某个属性值是一个函数,而不是一个字符串,该函数将被调用并且返回值后才会被序列化。

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
var escape = encodeURIComponent

function serialize(params, obj, traditional, scope){
var type, array = $.isArray(obj), hash = $.isPlainObject(obj)
$.each(obj, function(key, value) {
type = $.type(value)
if (scope) key = traditional ? scope :
scope + '[' + (hash || type == 'object' || type == 'array' ? key : '') + ']'
// handle data in serializeArray() format
if (!scope && array) params.add(value.name, value.value)
// recurse into nested objects
else if (type == "array" || (!traditional && type == "object"))
serialize(params, value, traditional, key)
else params.add(key, value)
})
}

$.param = function(obj, traditional){
var params = []
params.add = function(key, value) {
if ($.isFunction(value)) value = value()
if (value == null) value = ""
// console.log(escape(key))
this.push(escape(key) + '=' + escape(value))
}
serialize(params, obj, traditional)

// console.log(params)
return params.join('&').replace(/%20/g, '+')
}

其实现思路比较简单,对value进行encodeURIComponent()处理,在调用serialize()键值和属性值拼接并push进数组。最后利用join和replace 连接形成字符串

1
2
3
encodeURIComponent()是对统一资源标识符(URI)的组成部分进行编码的方法。
它使用一到四个转义序列来表示字符串中的每个字符的UTF-8编码
(只有由两个Unicode代理区字符组成的字符才用四个转义字符编码)。

附录:

event模块源码(注:此为拷贝版本,对应的是本博文的内容,最新版本请到zepto官网获取。)

示例代码:zepto.html