/**这个文件是对xmlhttp异步请求进行了简单的封装,*主要是将prototytp进行了简化,如果要使用复杂的功能可以使用prototype的ajax.js*外部使用时,主要调用方式为* var myAjax=new Ajax.Request( url, { method: 'get', asynchronous: true, onSuccess: function(xmlHttp) { }, onFailure:function(xmlHttp){ }, onException:function(exception){ } } ); 另可使用myAjax.header()和myAjax.evalResponse(); 其他的都为内部调用函数,外部尽量不要使用。*/
/**基础函数*Class.create()*Try.these()*Object.extend()*Function.prototype.bind*/var Class = { create: function() { return function() { this.initialize.apply(this, arguments); } }};var Try = { these: function() { var returnValue;
for (var i = 0; i < arguments.length; i++) { var lambda = arguments[i]; try { returnValue = lambda(); break; } catch (e) {} }
return returnValue; }};var Abstract = new Object();Object.extend = function(destination, source) { for (property in source) { destination[property] = source[property]; } return destination;};Function.prototype.bind = function(object) { var __method = this; return function() { __method.apply(object, arguments); }};/**基础ajax类*封装了一个函数:Ajax.getTransport()返回一个xmlhttp对象*这个类里的函数一般不使用。*/var Ajax = { getTransport: function() { return Try.these( function() {return new ActiveXObject('Msxml2.XMLHTTP')}, function() {return new ActiveXObject('Microsoft.XMLHTTP')}, function() {return new XMLHttpRequest()} ) || false; }};/**基础ajax.base类*封装了三个函数:*setOptions:设置进行ajax请求的参数*responseIsSuccess:判断异步请求返回是否成功*responseIsFailure:判断异步请求返回是否失败*这个类里的函数也没有必要在实际中使用,只有在扩展是才会使用到*/Ajax.Base = function() {};Ajax.Base.prototype = { setOptions: function(options) { this.options = { method: 'post',//异步请求方法,可以为get和post asynchronous: true, //设置是否为异步方式发送, parameters: '' //传递参数,参数都是url编码格式a=valueOfA&b=valueOfB } Object.extend(this.options, options || {});//以上三个属性为异步请求的基本属性。 }, responseIsSuccess: function() { return this.transport.status == undefined || this.transport.status == 0 || (this.transport.status >= 200 && this.transport.status < 300); }, responseIsFailure: function() { return !this.responseIsSuccess(); }};
Ajax.Request = Class.create();/**定义了xmlhttp请求的状态。*0 (未初始化) 对象已建立,但是尚未初始化(尚未调用open方法) *1 (初始化) 对象已建立,尚未调用send方法 *2 (发送数据) send方法已调用,但是当前的状态及http头未知 *3 (数据传送中) 已接收部分数据,因为响应及http头不全,这时通过responseBody和responseText获取部分数据会出现错误, *4 (完成) 数据接收完毕,此时可以通过通过responseBody和responseText获取完整的回应数据 */Ajax.Request.Events = ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];/**Ajax.Request对象,需要实例化对象,**/Ajax.Request.prototype = Object.extend(new Ajax.Base(),{ initialize: function(url, options) { this.transport = Ajax.getTransport();//返回xmlhttp对象this.setOptions(options);//设置请求的参数,在初始化时写 this.request(url);//进行异步请求 }, request: function(url) { var parameters = this.options.parameters || ''; if (parameters.length > 0) parameters += '&_=';
try { this.url = url; /*如果是get方法的化,就将parameters里的内容添加到url里*/ if (this.options.method == 'get' && parameters.length > 0) this.url += (this.url.match(/\?/) ? '&' : '?') + parameters; /*调用xmlhttp的请求函数,进行请求*/ this.transport.open(this.options.method, this.url, this.options.asynchronous);
/*如果是异步请求,对onreadystatechange绑定函数,对于为什么要用定时器,没10ms将状态设为Loading,我也没有明白。*/ if (this.options.asynchronous) { this.transport.onreadystatechange = this.onStateChange.bind(this); setTimeout((function() {this.respondToReadyState(1)}).bind(this), 10); } this.setRequestHeaders();//设置请求里的头部信息,包括编码等信息 /*对与post方式请求,也可以通过options里的postBody来设,这里就将postbody放到参数里进行传递*/ var body = this.options.postBody ? this.options.postBody : parameters; /*发送post数据*/ this.transport.send(this.options.method == 'post' ? body : null);
} catch (e) { this.dispatchException(e); } },setRequestHeaders: function() { var requestHeaders = ['X-Requested-With', 'XMLHttpRequest'];
if (this.options.method == 'post') { requestHeaders.push('Content-type', 'application/x-www-form-urlencoded');
/* Force "Connection: close" for Mozilla browsers to work around * a bug where XMLHttpReqeuest sends an incorrect Content-length * header. See Mozilla Bugzilla #246651. */ if (this.transport.overrideMimeType) requestHeaders.push('Connection', 'close'); }
if (this.options.requestHeaders) requestHeaders.push.apply(requestHeaders, this.options.requestHeaders);
for (var i = 0; i < requestHeaders.length; i += 2) this.transport.setRequestHeader(requestHeaders[i], requestHeaders[i+1]); },/**状态改变时,执行respondToReadyState,判断当状态为1时不执行。*/ onStateChange: function() { var readyState = this.transport.readyState; if (readyState != 1) this.respondToReadyState(this.transport.readyState); },/* *返回异步请求返回文件的头部信息,name表示名字,函数返回参数值 */ header: function(name) { try { return this.transport.getResponseHeader(name); } catch (e) {} }, /* *如果返回header信息里包括X-JSON/xxx,则会执行xxx的内容 *不是很明白这里,为什么要eval */ evalJSON: function() { try { return eval(this.header('X-JSON')); } catch (e) {} }, /* *很简单的函数,如果返回Content-type为text/javascript,则会调用此函数进行执行,我认为这处用途不大 */ evalResponse: function() { try { return eval(this.transport.responseText); } catch (e) { this.dispatchException(e); } },/* *根据返回的状态决定该执行的步骤 */ respondToReadyState: function(readyState) { var event = Ajax.Request.Events[readyState]; var transport = this.transport, json = this.evalJSON();
if (event == 'Complete') { /* *此处如果状态处于完成状态则会进行分析分别调用onSuccess和onFailure,所以一般onComplete不调用为好 */ try { (this.options['on' + this.transport.status] || this.options['on' + (this.responseIsSuccess() ? 'Success' : 'Failure')] || function(){})(transport, json); } catch (e) { this.dispatchException(e); } /*此处对返回js进行了eval*/ if ((this.header('Content-type') || '').match(/^text\/javascript/i)) this.evalResponse(); } try { (this.options['on' + event] || function(){})(transport, json); } catch (e) { this.dispatchException(e); } /* Avoid memory leak in MSIE: clean up the oncomplete event handler */ if (event == 'Complete') this.transport.onreadystatechange = function(){}; }, /* *错误时调用,一般外部使用onException:function(){} */ dispatchException: function(exception) { (this.options.onException || function(){})(this, exception); }
});
相关资源:Prototype源码浅析 Number部分