Jquery 实现原理之 Ajax

一:Jquery Ajax底层接口有:$.ajaxPrefilters、$.ajaxTransport、$.ajaxSettings、$ajaxSetup、$ajaxSettings;

  其中$.ajaxPrefilters 和 $.ajaxTransport是通过inspectPrefiltersOrTransports构造器来创建的;

$.ajaxPrefilters:是一个前置过滤器,在每个请求被$.ajaxTransport()和$.ajax()处理之前调用,设置自定义ajax选项或者修改现有的选项,简单说就是hack的  做法,但是比事件处理的hack的手法更加高明。可以用来处理参数,注册回调等。

例如:改变代理服务器的域请求

 $.ajaxPrefilter("+*", function( options ) {
if ( options.crossDomain ) {
options.url = "http://mydomain.net/proxy/" + encodeURIComponent( options.url );
options.crossDomain = false;
}
});

$.ajaxTransport:是一个请求分发器,是发送请求的具体实现,比如xhr就用xmlhttprequest来实现,script就是通过head中插入script标签来实现.

例如:用来拦截发送的请求

 $.ajaxTransport("+*", function(options, originalOptions, jqXHR) {
return {
send: function(headers, completeCallback) {
var status = 404;
var statusText = "error";
var response = {
text: ""
};
var item = {            
url: "/paapi/v1/datapoints/pa",
data: data.groupsdatapoint
};
if (!item) {
console.log("require mock data: \n" + originalOptions.url);
} else {
status = 200;
statusText = "ok";
var data = item.data;
response.text = data;
}
setTimeout(function() {
completeCallback(status, statusText, response);
}, 0);
}
};
});

二: 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()方法如下:

 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);
}
}
}
};
}

该函数功能就是把某一个dataType对应的处理函数func存进structure中,实际就是一个简单的注册事件。

 // 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函数而已。

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对象
上一篇:轻量级的原型设计工具-Axure RP


下一篇:MyBatis的学习总结四:实现关联表查询【参考】