一:Jquery Ajax底层接口有:$.ajaxPrefilters、$.ajaxTransport、$.ajaxSettings、$ajaxSetup、$ajaxSettings;
其中$.ajaxPrefilters 和 $.ajaxTransport是通过inspectPrefiltersOrTransports构造器来创建的;
$.ajaxPrefilters:是一个前置过滤器,在每个请求被$.ajaxTransport()和$.ajax()处理之前调用,设置自定义ajax选项或者修改现有的选项,简单说就是hack的 做法,但是比事件处理的hack的手法更加高明。可以用来处理参数,注册回调等。
例如:改变代理服务器的域请求
1 $.ajaxPrefilter("+*", function( options ) { 2 if ( options.crossDomain ) { 3 options.url = "http://mydomain.net/proxy/" + encodeURIComponent( options.url ); 4 options.crossDomain = false; 5 } 6 });
$.ajaxTransport:是一个请求分发器,是发送请求的具体实现,比如xhr就用xmlhttprequest来实现,script就是通过head中插入script标签来实现.
例如:用来拦截发送的请求
1 $.ajaxTransport("+*", function(options, originalOptions, jqXHR) { 2 return { 3 send: function(headers, completeCallback) { 4 var status = 404; 5 var statusText = "error"; 6 var response = { 7 text: "" 8 }; 9 var item = { 10 url: "/paapi/v1/datapoints/pa", 11 data: data.groupsdatapoint 12 }; 13 if (!item) { 14 console.log("require mock data: " + originalOptions.url); 15 } else { 16 status = 200; 17 statusText = "ok"; 18 var data = item.data; 19 response.text = data; 20 } 21 setTimeout(function() { 22 completeCallback(status, statusText, response); 23 }, 0); 24 } 25 }; 26 });
二: ajax的实现
实现ajax的目的是什么?
实现ajax的目的主要是对不同的dataType的具体处理和实现,比如'jsonp'应该怎么处理,'script'怎么处理,'*'怎么处理;
对此ajax模块的做法是,提供一个基本的模块ajax,然后通过插件形式来实现对不同dataType的处理。
ajax暴露ajaxPrefilter: addToPrefiltersOrTransports( prefilters ) , ajaxTransport: addToPrefiltersOrTransports( transports )是给插件用的,可以注册自己的dataType处理函数。
其中prefilters={'jsonp': function() {}, '*': function(){}, 'script':function(){}}可能是这样的,ajax在每个请求发送之前,根据dataType调用prefilters中的函数进行预处理,然后调用transport中的对应函数来发送请求。
addToPrefiltersOrTransports()方法如下:
1 function addToPrefiltersOrTransports(structure) { 2 3 // dataTypeExpression is optional and defaults to "*" 4 return function(dataTypeExpression, func) { 5 6 if (typeof dataTypeExpression !== "string") { 7 func = dataTypeExpression; 8 dataTypeExpression = "*"; 9 } 10 11 var dataType, 12 i = 0, 13 dataTypes = dataTypeExpression.toLowerCase().match(rnotwhite) || []; 14 15 if (jQuery.isFunction(func)) { 16 // For each dataType in the dataTypeExpression 17 while ((dataType = dataTypes[i++])) { 18 // Prepend if requested 19 if (dataType[0] === "+") { 20 dataType = dataType.slice(1) || "*"; 21 (structure[dataType] = structure[dataType] || []).unshift(func); 22 23 // Otherwise append 24 } else { 25 (structure[dataType] = structure[dataType] || []).push(func); 26 } 27 } 28 } 29 }; 30 }
该函数功能就是把某一个dataType对应的处理函数func存进structure中,实际就是一个简单的注册事件。
1 // Base inspection function for prefilters and transports 2 function inspectPrefiltersOrTransports(structure, options, originalOptions, jqXHR) { 3 4 var inspected = {}, 5 seekingTransport = (structure === transports); 6 7 function inspect(dataType) { 8 var selected; 9 inspected[dataType] = true; 10 jQuery.each(structure[dataType] || [], function(_, prefilterOrFactory) { 11 var dataTypeOrTransport = prefilterOrFactory(options, originalOptions, jqXHR); 12 if (typeof dataTypeOrTransport === "string" && !seekingTransport && !inspected[dataTypeOrTransport]) { 13 options.dataTypes.unshift(dataTypeOrTransport); 14 inspect(dataTypeOrTransport); 15 return false; 16 } else if (seekingTransport) { 17 return !(selected = dataTypeOrTransport); 18 } 19 }); 20 return selected; 21 } 22 23 return inspect(options.dataTypes[0]) || !inspected["*"] && inspect("*"); 24 } 25 }
该代码时取调用dataType对应的prefilters和transports函数而已。
Ajax完成一部请求的全过程:
- 创建了一个jqXHR对象,这个对象就是ajax的返回值
- 用deferred对象封装jqXHR对象,因此可以实现链式的异步操作:xhr.complete(x).success(x).errorl(x),这里的complete,success和error就是promise对象的add, done和fail的别名而已。
- 调用函数inspectPrefiltersOrTransports( prefilters, s, options, jqXHR ),那些插件注册的prefilters函数就在这里被调用了。
- 做了一大对后续的处理,比如设置header参数,设置缓存cache
- 调用inspectPrefiltersOrTransports( transports, s, options, jqXHR )函数发送请求
- 定义了done函数,当请求发送结束之后做后续处理,包括调用convert转换结果、设置statusText,调用deferred.resolveWith触发异步回调等
- 最后返回了jqXHR对象