ajax模块的结构:
默认配置 ajaxSettings,并可拓展自定义的配置
构造 ajaxPrefilters 和 ajaxTransport,这两个都是key-value对象,其中key是dataType,value是对应的处理函数。
ajaxPrefilters 是一个过滤器,作用是在发送ajax请求之前做一定的预处理工作,比如:处理参数,注册回调等。
ajaxTransport是一个分发器,是发送请求的具体实现,比如xhr就用xmlhttprequest来实现,script就通过在head中插入script标签来实现。
2,ajax插件
通过自定义这两个配置,可以以插件形式实现自己的ajax函数。实际上,ajax.js并没有提供任何具体实现,而ajax/目录下通过插件形式实现了四种方法:jsonp, load, script, xhr。
比如script插件,定义了自己的settings,定义了自己的ajaxPrefilter,以及ajaxTransport,主要的实现就是在ajaxTransport函数中在head中插入script标签。
实现一个ajax最主要的是什么?
显然是对不同dataType的具体处理和实现,比如'jsonp'应该怎么处理,'script'应该怎么处理,'*'应该怎么处理?
对此,ajax模块的做法是,提供一个基本模块ajax,然后通过插件形式来实现对各种不同dataType的具体处理。
下面逐段来分析ajax.js中的重要代码
prefilters = {},
transports = {},
这两行代码定义了两个非常重要的对象,prefilters就是预处理器,在ajax请求发出之前做预处理工作,transports是分发器,负责实际发送ajax请求。
这两个对象的结构是完全一样的,就是key-value类型,其中key表示datatype,value表示对应的处理函数。比如prefilter可能是这样的
{'jsonp': function() {}, '*': function(){}, 'script':function(){}}
ajax会在每个请求发送前,根据datatype调用prefilters中的对应函数进行预处理,然后调用transports中的对应函数来发送请求。
所以,如果没有ajax目录下的插件,ajax.js是没有提供实际的异步请求功能的。
function addToPrefiltersOrTransports( structure ) {
// dataTypeExpression is optional and defaults to "*"
return function( dataTypeExpression, func ) {
if ( typeof dataTypeExpression !== "string" ) {
func = dataTypeExpression;
dataTypeExpression = "*";
}
var dataType,
i = 0,
dataTypes = dataTypeExpression.toLowerCase().match( rnotwhite ) || [];
if ( jQuery.isFunction( func ) ) {
// For each dataType in the dataTypeExpression
while ( (dataType = dataTypes[i++]) ) {
// Prepend if requested
if ( dataType[0] === "+" ) {
dataType = dataType.slice( 1 ) || "*";
(structure[ dataType ] = structure[ dataType ] || []).unshift( func );
// Otherwise append
} else {
(structure[ dataType ] = structure[ dataType ] || []).push( func );
}
}
}
};
}
这个函数功能非常简单,就是把某一个dataype对应的处理函数func存进structure中,就是一个简单的注册而已。那么structure是什么呢?从后面的代码
ajaxPrefilter: addToPrefiltersOrTransports( prefilters ),
ajaxTransport: addToPrefiltersOrTransports( transports ),
可以得知就是prefilter和transports,因为他们的结构实际上完全一样,所以通过调用同一个函数addToPrefiltersOrTransports来实现的。
// Base inspection function for prefilters and transports
function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) {
var inspected = {},
seekingTransport = ( structure === transports );
function inspect( dataType ) {
var selected;
inspected[ dataType ] = true;
jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) {
var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR );
if( typeof dataTypeOrTransport === "string" && !seekingTransport && !inspected[ dataTypeOrTransport ] ) {
options.dataTypes.unshift( dataTypeOrTransport );
inspect( dataTypeOrTransport );
return false;
} else if ( seekingTransport ) {
return !( selected = dataTypeOrTransport );
}
});
return selected;
}
return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" );
}
上面是另一个重要函数,同样很简单,它的功能就是去调用datatype对应的prefilters和transports函数而已。
// Attach a bunch of functions for handling common AJAX events
jQuery.each( [ "ajaxStart", "ajaxStop", "ajaxComplete", "ajaxError", "ajaxSuccess", "ajaxSend" ], function( i, type ){
jQuery.fn[ type ] = function( fn ){
return this.on( type, fn );
};
});
这里注册了一堆快捷方式,所以你用xhr.ajaxStop(fn) 和 xhr.on('ajaxSropt', fun)是完全一样的。
下面就开始调用jquery.extend来在jquery上拓展一些ajax方法了。
ajaxSettings: {…..}
默认设置,具体参见源码
ajaxPrefilter: addToPrefiltersOrTransports( prefilters ),
ajaxTransport: addToPrefiltersOrTransports( transports ),
上面提到过的,两个方法暴漏出来是给查件用的,可以注册自己对datatype的处理函数,很简单不多说。
在下面就是ajax函数 函数有点长就不贴了主要做了这些事:
1,创建了一个jqXHR对象,这个对象就是ajax的返回值
2,用deferred对象封装jqXHR对象,因此可以实现链式的异步操作:xhr.complete(x).success(x).errorl(x),这里的complete,success和error就是promise对象的add, done和fail的别名而已。
3,调用函数inspectPrefiltersOrTransports( prefilters, s, options, jqXHR ),那些插件注册的prefilters函数就在这里被调用了。
4,做了一大对后续的处理,比如设置header参数,设置缓存cache
5,调用inspectPrefiltersOrTransports( transports, s, options, jqXHR )函数发送请求
6,定义了done函数,当请求发送结束之后做后续处理,包括调用convert转换结果、设置statusText,调用deferred.resolveWith触发异步回调等
7,最后返回了jqXHR对象
jQuery.each( [ "get", "post" ], function( i, method ) {
jQuery[ method ] = function( url, data, callback, type ) {
// shift arguments if data argument was omitted
if ( jQuery.isFunction( data ) ) {
type = type || callback;
callback = data;
data = undefined;
}
return jQuery.ajax({
url: url,
type: method,
dataType: type,
data: data,
success: callback
});
};
});
上面又是一个快捷方式,get和post就是参数不同的ajax函数而已
function ajaxConvert( s, response, jqXHR, isSuccess ) {}
这个函数就是根据setting中的设置来对请求结果进行类型转换
over,以上就是ajax的全部实现
比如xhr.js
jQuery.ajaxTransport(function( options ) {
var callback;
// Cross domain only allowed if supported through XMLHttpRequest
if ( jQuery.support.cors || xhrSupported && !options.crossDomain ) {
return {
send: function( headers, complete ) {
….
},
abort: function() {
...
}
};
}
});
上面就是其主要实现函数的结构,注意这里没有dataType参数,没有dataType就相当于"*",就是对所有请求的默认处理函数,其中的实现就是通过新建XMLHTTPRequest对象来发送请求
一, ajax 实现包括两个部分
1 基本模块ajax,一个ajax.js定义了异步请求的基本结构,主要提供了两个重要的配置默认配置 ajaxSettings,并可拓展自定义的配置
构造 ajaxPrefilters 和 ajaxTransport,这两个都是key-value对象,其中key是dataType,value是对应的处理函数。
ajaxPrefilters 是一个过滤器,作用是在发送ajax请求之前做一定的预处理工作,比如:处理参数,注册回调等。
ajaxTransport是一个分发器,是发送请求的具体实现,比如xhr就用xmlhttprequest来实现,script就通过在head中插入script标签来实现。
2,ajax插件
通过自定义这两个配置,可以以插件形式实现自己的ajax函数。实际上,ajax.js并没有提供任何具体实现,而ajax/目录下通过插件形式实现了四种方法:jsonp, load, script, xhr。
比如script插件,定义了自己的settings,定义了自己的ajaxPrefilter,以及ajaxTransport,主要的实现就是在ajaxTransport函数中在head中插入script标签。
二,ajax的实现
下面我们主要探讨ajax.js的实现。实现一个ajax最主要的是什么?
显然是对不同dataType的具体处理和实现,比如'jsonp'应该怎么处理,'script'应该怎么处理,'*'应该怎么处理?
对此,ajax模块的做法是,提供一个基本模块ajax,然后通过插件形式来实现对各种不同dataType的具体处理。
下面逐段来分析ajax.js中的重要代码
prefilters = {},
transports = {},
这两行代码定义了两个非常重要的对象,prefilters就是预处理器,在ajax请求发出之前做预处理工作,transports是分发器,负责实际发送ajax请求。
这两个对象的结构是完全一样的,就是key-value类型,其中key表示datatype,value表示对应的处理函数。比如prefilter可能是这样的
{'jsonp': function() {}, '*': function(){}, 'script':function(){}}
ajax会在每个请求发送前,根据datatype调用prefilters中的对应函数进行预处理,然后调用transports中的对应函数来发送请求。
所以,如果没有ajax目录下的插件,ajax.js是没有提供实际的异步请求功能的。
function addToPrefiltersOrTransports( structure ) {
// dataTypeExpression is optional and defaults to "*"
return function( dataTypeExpression, func ) {
if ( typeof dataTypeExpression !== "string" ) {
func = dataTypeExpression;
dataTypeExpression = "*";
}
var dataType,
i = 0,
dataTypes = dataTypeExpression.toLowerCase().match( rnotwhite ) || [];
if ( jQuery.isFunction( func ) ) {
// For each dataType in the dataTypeExpression
while ( (dataType = dataTypes[i++]) ) {
// Prepend if requested
if ( dataType[0] === "+" ) {
dataType = dataType.slice( 1 ) || "*";
(structure[ dataType ] = structure[ dataType ] || []).unshift( func );
// Otherwise append
} else {
(structure[ dataType ] = structure[ dataType ] || []).push( func );
}
}
}
};
}
这个函数功能非常简单,就是把某一个dataype对应的处理函数func存进structure中,就是一个简单的注册而已。那么structure是什么呢?从后面的代码
ajaxPrefilter: addToPrefiltersOrTransports( prefilters ),
ajaxTransport: addToPrefiltersOrTransports( transports ),
可以得知就是prefilter和transports,因为他们的结构实际上完全一样,所以通过调用同一个函数addToPrefiltersOrTransports来实现的。
// Base inspection function for prefilters and transports
function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) {
var inspected = {},
seekingTransport = ( structure === transports );
function inspect( dataType ) {
var selected;
inspected[ dataType ] = true;
jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) {
var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR );
if( typeof dataTypeOrTransport === "string" && !seekingTransport && !inspected[ dataTypeOrTransport ] ) {
options.dataTypes.unshift( dataTypeOrTransport );
inspect( dataTypeOrTransport );
return false;
} else if ( seekingTransport ) {
return !( selected = dataTypeOrTransport );
}
});
return selected;
}
return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" );
}
上面是另一个重要函数,同样很简单,它的功能就是去调用datatype对应的prefilters和transports函数而已。
// Attach a bunch of functions for handling common AJAX events
jQuery.each( [ "ajaxStart", "ajaxStop", "ajaxComplete", "ajaxError", "ajaxSuccess", "ajaxSend" ], function( i, type ){
jQuery.fn[ type ] = function( fn ){
return this.on( type, fn );
};
});
这里注册了一堆快捷方式,所以你用xhr.ajaxStop(fn) 和 xhr.on('ajaxSropt', fun)是完全一样的。
下面就开始调用jquery.extend来在jquery上拓展一些ajax方法了。
ajaxSettings: {…..}
默认设置,具体参见源码
ajaxPrefilter: addToPrefiltersOrTransports( prefilters ),
ajaxTransport: addToPrefiltersOrTransports( transports ),
上面提到过的,两个方法暴漏出来是给查件用的,可以注册自己对datatype的处理函数,很简单不多说。
在下面就是ajax函数 函数有点长就不贴了主要做了这些事:
1,创建了一个jqXHR对象,这个对象就是ajax的返回值
2,用deferred对象封装jqXHR对象,因此可以实现链式的异步操作:xhr.complete(x).success(x).errorl(x),这里的complete,success和error就是promise对象的add, done和fail的别名而已。
3,调用函数inspectPrefiltersOrTransports( prefilters, s, options, jqXHR ),那些插件注册的prefilters函数就在这里被调用了。
4,做了一大对后续的处理,比如设置header参数,设置缓存cache
5,调用inspectPrefiltersOrTransports( transports, s, options, jqXHR )函数发送请求
6,定义了done函数,当请求发送结束之后做后续处理,包括调用convert转换结果、设置statusText,调用deferred.resolveWith触发异步回调等
7,最后返回了jqXHR对象
jQuery.each( [ "get", "post" ], function( i, method ) {
jQuery[ method ] = function( url, data, callback, type ) {
// shift arguments if data argument was omitted
if ( jQuery.isFunction( data ) ) {
type = type || callback;
callback = data;
data = undefined;
}
return jQuery.ajax({
url: url,
type: method,
dataType: type,
data: data,
success: callback
});
};
});
上面又是一个快捷方式,get和post就是参数不同的ajax函数而已
function ajaxConvert( s, response, jqXHR, isSuccess ) {}
这个函数就是根据setting中的设置来对请求结果进行类型转换
over,以上就是ajax的全部实现
三,插件的实现
有了ajax这个基本模块,那么实现各种插件就非常简单明了,就是要通过ajaxPrefilter和ajaxTransport来注册对应dataType的处理函数就ok了。比如xhr.js
jQuery.ajaxTransport(function( options ) {
var callback;
// Cross domain only allowed if supported through XMLHttpRequest
if ( jQuery.support.cors || xhrSupported && !options.crossDomain ) {
return {
send: function( headers, complete ) {
….
},
abort: function() {
...
}
};
}
});
上面就是其主要实现函数的结构,注意这里没有dataType参数,没有dataType就相当于"*",就是对所有请求的默认处理函数,其中的实现就是通过新建XMLHTTPRequest对象来发送请求