要成功利用Ajax的异步性优势,就必须为每个HttpRequest注册独立的处理函数,而为了使javascript代码可被java程序生成,必须为每个处理函数命名,在这一点上,面向对象的包或命名空间的概念为我们提供了很好的参考。
可以直接延用这一规则,于是想到了javascript的面向对象特性。现在考虑一个类Ajax,其封装了HttpRequest。在这一实现上,一般将HttpRequest作为Ajax类的一个域req,对每个Ajax实例ajaxObject,为其域ajaxObject.req注册onstatechange处理函数,该函数最好是ajaxObject的一个function域或void行为。于是想到了下面的语句:
Ajax.prototype.submit=function(){
this.status="ready";
this.req.onreadystatechange = this.processRequest;
this.req.open("GET",this.url,true);
this.req.send(this.body);
}
Ajax.prototype.processRequest=function(){
process(this);
}
但这是行不通的,因为processRequest此时仅仅是一个函数的引用,它没有this这个对象了。
那么如何解决这个问题呢?
Ruby使用了一系列复杂的对象使Ajax类能够绑定(bind)this,使this能作为参数传入processRequest,但个人认为作为一个公用模块尽量不要使用如此多的限定(类继承关系复杂)。
我的解决方法是用一个池(AjaxFactory)来生成并维护一组Ajax实例,每个Ajax实例有一个唯一的name,于是可以通过自己的name到AjaxFactory中取得对自己的引用。
下面是AjaxFactory的源程序:
/**
*
*AjaxFactory,负责生产并维护Ajax类实例
*
*
*/
function DefaultAjaxFactory(){
this.map=new Map();
}
DefaultAjaxFactory.prototype.createAjax=function(name){
var ajax=new Ajax(name);
this.map.put(name,ajax);
return ajax;
}
DefaultAjaxFactory.prototype.getAjax=function(name){
return this.map.get(name);
}
其中Map的使用类似于java的java.util.HashMap,关于Map等数据结构的类请看我的其他文章。
程序在使用的时候可以这样写:
var AjaxFactory=new DefaultAjaxFactory();
var ajaxObject=AjaxFactory.createAjax("ajaxObject");
这样就生成了一个Ajax的实例ajaxObject。
下面是Ajax的实现:
/*
*
*
*Ajax ,异步化提交一个请求并获得结果(对象或数组)
*
*
*/
function Ajax(name){
this.req=new ActiveXObject("Msxml2.XMLHTTP");
this.name=name;
this.xmlDoc=null;
this.status="ready";
this.url="";
this.body="";
this.doSuccess=function(){return null;};
this.doFail=function(){return null;};
this.object=new XMLObject();
}
Ajax.prototype.submit=function(){
this.status="ready";
//注意这一句,这就是注册statechange处理函数的语句
this.req.onreadystatechange = new Function("var temp_ajax=AjaxFactory.getAjax(/""+this.name+"/");temp_ajax.processResponse()");
this.req.open("GET",this.url,true);
this.req.send(this.body);
}
Ajax.prototype.processResponse=function(){
if(this.req.readyState==4){
if(this.req.status==200){
this.status="success";
this.preHandleSuccess();
this.doSuccess();
}else{
this.status="fail";
this.preHandleFail();
this.doFail();
}
}
}
Ajax.prototype.setSuccessHandler=function(successFunc){
this.doSuccess=successFunc;
}
Ajax.prototype.setFailHandler=function(failFunc){
}
Ajax.prototype.preHandleSuccess=function(){
//fire after process succeeded
var xmlDoc=this.req.responseXML.getElementsByTagName("Object")[0];
this.visitTree(xmlDoc);
}
Ajax.prototype.preHandleFail=function(){
//fire after process failed
}
Ajax.prototype.visitTree=function(root){//遍历node tree将xml nodes转换为javascript对象
if(root.hasChildNodes){
objname=root.tagName;
this.object.addProperty(objname);
for(var i=0;i<root.childNodes.length;i++){
var node=root.childNodes[i];
this.visitTree(node);
}
}else{
var objvalue=root.nodeValue;
this.object.setProperty(objvalue);
}
}
/*for it is not synchronized,please call the following functions in your success handlers*/
Ajax.prototype.getObject=function(){
return this.object.Object[0];
}
Ajax.prototype.getQuery=function(){
var obj=this.getObject();
var res=new Array();
return res;
}
/* end */
/*usage:
function ss(){//成功处理函数
var obj=this.getObject();
}
var ajax=AjaxFactory.createAjax("abc1");
ajax.url="http://localhost:8080/UserAdmin/servlet/AjaxDispatcher?DspId=999999";
ajax.setSuccessHandler(ss);//注册处理函数
ajax.submit();
*/