在AJAX编程中离不开对XMLHttpRequest对象的使用。XMLHttpRequest对象代表了浏览器和服务器之间的通讯,并可采用异步模式。浏览器通过XMLHttpRequest在后台发起请求,然后通过其属性onreadystatechange注册的回调函数来异步处理应答。编程步骤如下:
1. 创建XMLHttpRequest对象xhr;
2. 调用xhr的open方法打开资源;
3. 通过xhr的属性onreadystatechange注册回调函数;
4. 通过xhr的方法setRequestHeader设置相应请求头;
5. 调用xhr的send方法发起请求。
从上我们可以看到,编程步骤固定,在某些步骤中有些许的变化。由此我们可以联想到模板(template)和回调(callback)编程模式。在此处的回调依赖于xhr的状态变化,我们可以在模板与回调的基础之上采用观察者模式来封装,从而达到代码的从用和简化编程。
在这里,事件源实际上就是XMLHttpRequest的对象,我将它封装到Request类型;事件是XMLHttpRequest对象的状态readyState;而回调函数是事件处理器,我用RequestListener和RequestAdapter进行封装。一下是程序的代码:
/**
*用于XMLHttpRequest(xhr)回调, 根据xhr的readyState
*调用不同的函数
*/
function RequestListener(){
/*
*当xhr.readyState = 0时调用
*/
this.uninitialized = function(){}
/*
*当xhr.readyState = 1时调用
*/
this.loading = function(){}
/*
*当xhr.readyState = 2时调用
*/
this.loaded = function(){}
/*
*当xhr.readyState = 3时调用
*/
this.interactive = function(){}
/*
*当xhr.readyState = 4时调用
*/
this.complete = function(status, statusText, responseText, responseXML){} }
/**
*RequestListener的子类型,用于扩展complet方法,
*当HTTP(xhr.status)应答状态为200时, 调用handleText和handleXML
*处理应答体;当状态为其它时,调用handleError.
*/
function RequestAdapter(){
this.complete = function(status, statusText, responseText, responseXML){
if(status == 200){
this.handleText(responseText);
this.handleXML(responseXML);
}else{
this.handleError(status, statusText);
}
}
this.handleText = function(text){}
this.handleXML = function(xml){}
this.handleError = function(status, statusText){ alert("Http status: " + status + " , " + statusText); }
}
RequestAdapter.prototype = new RequestListener();
RequestAdapter.prototype.constructor = RequestAdapter;
/**
*封装XMLHttpRequest,回调RequestListener的不同方法处理
*不同的应答状态.对外提供doGet, doPost方法处理不同方式的请求.
*使用例子如下:
* var l = new RequestAdapter();
* l.handleText = function(text){alert(text);}
* var req = new Request(l);
* req.doGet("hello.jsp");
*/
function Request(l){
var xhr = createXhr();
var listener = l;
if(!listener){ listener = new RequestListener(); }
this.setListener = function(l){listener = l;}
this.doGet = function(url, asyn){ doProcess("GET", url, null, asyn); }
this.doPost = function(url, reqBody, asyn){ doProcess("POST", url, reqBody, asyn); }
function doProcess(method, url, reqBody, asyn){
if(asyn == undefined){ asyn = true }
xhr.open(method, url, asyn);
if(asyn){ xhr.onreadystatechange = callback; }
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xhr.send(reqBody);
if(!asyn){ listener.complete(xhr.status, xhr.statusText, xhr.responseText, xhr.responseXML); }
}
function callback(){
switch(xhr.readyState){
case 0: listener.uninitialized(); break;
case 1: listener.loading(); break;
case 2: listener.loaded(); break;
case 3: listener.interactive(); break;
case 4: listener.complete(xhr.status, xhr.statusText, xhr.responseText, xhr.responseXML);
}
}
}
function createXhr(){
if(window.ActiveXObject){
return new ActiveXObject("Microsoft.XMLHTTP");
}else if(window.XMLHttpRequest){
return new XMLHttpRequest();
}else{ throw new Error("Does not ajax programming"); }
}