2019独角兽企业重金招聘Python工程师标准>>>
一、从ajax调用出发
$.ajax({
url:"http://www.microsoft.com", //设置请求的url
dataType:"json", //设置数据返回格式为json
async:true,//设置请求是否异步,默认为异步。
data:{"id":"value"}, //设置发送的数据
type:"GET", //设置请求方式
beforeSend:function(){
//设置请求前的回调
},
success:function(req){
//设置请求成功后的回调
},
complete:function(){
//设置请求完成后的回调
},
error:function(){
//设置请求出错处理的回调
}
});
从ajax标准的请求调用代码中我们看到传入了一个参数,这个参数是一个对象。对象中定义了XMLHttpRequest对象所需的数据集合。
二、万变不离其宗:了解本质
我们知道.ajax()是jQuery对XMLHttpRequest对象发送HTTP请求的一个js封装接口,所以总归要做一下几部:创建XMLHttpRequest对象,然后open进行tcp链接,其次添加相关的头部信息和定义回调函数等等设置,最后send给服务器并携带相关数据。
xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange=callback;
xmlhttp.open("POST","test.do",true);
// // 设置POST请求的请求头
xmlhttp.setRequestHeader("Content-Type"
, "application/json");
xmlhttp.send('password=123&username=mingzi');
三、ajax()在jQuery中哪里定义
如图所示,ajax定义在.extend()函数调用的唯一参数对象中,我们前面解读extend源码的时候知道,如果extend函数中只有一个参数(对象)的时候,这个参数就是源对象,jQuery为目标对象。这样等效于在jQuery对象上扩展这个源对象的所有属性,其中之一的ajax就被扩展到jQuery对象上,成为jQuery静态工具函数的其中一员。
四、拆解.ajax()函数
1. .ajax()方法执行的6个关键步骤:
1)构造完整的请求选项集,并修正选项。【预处理AJAX所有数据合并用户定义的数据和默认数据】
2)构造jqXHR对象,并增加异步队列的行为。【http头部数据】
3)构造回调函数done(status,nativeStatusText,responses,headers),响应完成之后被调用,负责转换数据类型、执行回调函数、触发全局事件。【回调函数模型,处理所有状态的回调】
4)应用前置过滤器,继续修正选项。【数据处理】
5)获取请求发送器,并调用方法send(requestHeaders,done)发送请求。【创建XMLHttpRequest对象及open、send及回调处理等方法】
6)最后返回jqXHR对象。
2、构造完整的请求选项集
1)传进来的参数对象预处理
A. 如果第一个参数是对象类型,那option 就直接等于 第一个参数 url。然后消灭url = undefined。
B. 通过与一个空对象()进行或运算,强制option为一个对象!
ajax: function( url, options ) {
// If url is an object, simulate pre-1.5 signature
if ( typeof url === "object" ) {
options = url;
url = undefined;
}
// Force options to be an object
options = options || {};
s = jQuery.ajaxSetup( {}, options ),
}
2) 创建最终选项对象(XMLHttpRequest所需的数据集):将传进来的对象与默认选项对象进行深度合并。
A. jQuery.ajaxSetup — ajaxExtend() —— jQuery.ajaxSettings——jQuery.ajaxSettings.flatOptions
B. 简而言之是通过以上的几个函数调用将默认选项对象jQuery.ajaxSettings和用户自定义的ajax参数(选项对象)通过ajaxExtend进行深度合并(除了url和context不深度外),得到一个最终的选项对象s。如下:
3. 构造jqXHR对象
jqXHR对象是浏览器原生XMLHttpRequest对象的超集,当请求发送器不是XMLHttpRequest时,jqXHR对象会尽可能地模拟XMLHttpRequest的功能。并且,jqXHR对象还具备异步队列的方法和行为。为了兼容XMLHttpRequest,jqXHR对象暴露了以下属性和方法:
❑readyState:表示当前jqXHR对象的状态。
❑status:响应的HTTP状态码。
❑statusText:响应的HTTP状态描述。
❑responseText、responseXML:响应的文本内容、XML文档。
❑setRequestHeader(name,value):设置请求头 […]❑getAllResponseHeaders():获取响应头字符串。
❑getResponseHeader(key):获取指定名称的响应头的值。
❑overrideMimeType(type):用于覆盖MIME类型。
❑abort(statusText):取消本次请求。
4. done构造函数!
1)在.ajax()函数中根据需要直接调用done;
2)传入发送器的send()函数当send的回调函数对发送数据完成后回调执行。
transport.send( requestHeaders, done );
//传入整个done回调函数放到transport.send(参数中
send: function( headers, complete ) {
//定义发送器send中的回调函数Callback
callback = function( type ) {
return function() {
if ( callback ) {
if ( type === "abort" ) {
xhr.abort();
} else if ( type === "error" ) {
complete( 0, "error" );
} else {
complete(
xhrSuccessStatus[ xhr.status ] || xhr.status,
xhr.statusText,
( xhr.responseType || "text" ) !== "text" ||
typeof xhr.responseText !== "string" ?
{ binary: xhr.response } :
{ text: xhr.responseText },
xhr.getAllResponseHeaders()
// Listen to events
//启动回调函数的监听
xhr.onload = callback();
5、数据处理:应用前置过滤器,继续修正选项
1)常规的:
s.url = ( ( url || s.url || location.href ) + "" )
.replace( rprotocol, location.protocol + "//" );
// Alias method option to type as per ticket #12004
s.type = options.method || options.type || s.method || s.type;
2)应用前置过滤器继续修正选项对象
prefilters = {},//空过滤器
ajaxPrefilter: addToPrefiltersOrTransports( prefilters ),//向对象prefilters中添加前置过滤器
inspectPrefiltersOrTransports( prefilters, s, options, jqXHR );//从对象prefilters中找到数据类型对应的前置过滤器数组,逐个执行
6. 发送器
1)我们可以从以下代码中看到transports发送器中含有XMLHttpRequest对象,及open创建网络链接、send()发送和abort()取消发送方法,还有执行回调函数complete 。
2)一次send的执行:transport.send( requestHeaders, done ); done是一个回调函数模型。可以执行各种http状态的回调!
transports = {},
ajaxTransport: addToPrefiltersOrTransports( transports ),
//通过inspectPrefiltersOrTransports获取发送器
transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );
//发送器实体
jQuery.ajaxTransport( function( options ) {
var callback, errorCallback;
// Cross domain only allowed if supported through XMLHttpRequest
if ( support.cors || xhrSupported && !options.crossDomain ) {
return {
send: function( headers, complete ) {
//构造XMLHttpRequest对象放在发送器里
var i,xhr = options.xhr();
xhr.open(options.type,options.url,options.async,options.username,options.password);
// Set headers
for ( i in headers ) {
xhr.setRequestHeader( i, headers[ i ] );
}
// Callback
callback = function( type ) {
return function() {
if ( callback ) {
callback = errorCallback = xhr.onload =
xhr.onerror = xhr.onabort = xhr.onreadystatechange = null;
if ( type === "abort" ) {
xhr.abort();
} else if ( type === "error" ) {
complete(
xhr.status,
xhr.statusText
);
}
} else {
complete(
xhrSuccessStatus[ xhr.status ] || xhr.status,
xhr.statusText,
( xhr.responseType || "text" ) !== "text" ||
typeof xhr.responseText !== "string" ?
{ binary: xhr.response } :
{ text: xhr.responseText },
xhr.getAllResponseHeaders()
);
}
}
};
};
xhr.onload = callback();
},
abort: function() {
if ( callback ) {
callback();
}
}
};
}
} );
//构造XMLHttpRequest对象放在发送器里
options.xhr() = jQuery.ajaxSettings.xhr = function() {
try {
return new window.XMLHttpRequest();
} catch ( e ) {}
};