zl程序教程

您现在的位置是:首页 >  前端

当前栏目

javascript构建一个xmlhttp对象池合理创建和使用xmlhttp对象

JavaScript对象 使用 一个 创建 构建 合理 XMLHTTP
2023-06-13 09:14:15 时间
如果我们在客户端频繁使用ajax技术,那么我们就不得不多次创建xmlhttp对象。当然,如您所知,我们可以改进创建的方式,比如使用全局变量来缓存一个实例(客户端的单例模式?!),对于同步方式的通信,这是很有效的,但是这样的方式对于异步通信会出现问题,因为没有了进程的堵塞,用户可能在上一次通信未完成时再次调用同一个xmlhttp实例,这样不等前一个调用的回调函数触发,前一次调用就被“覆盖”掉了(也就代表前一次调用失败)。建立一个保持xmlhttp实例的池,好处显而易见,最明显的优点就是我们不会创建冗余对象,同时也不会出现在同一个正在被调用的xmlhttp实例上出现再次被操作的情况。

具体实现思路:
我们使用一个数组来存储已创建的xmlhttp对象实例,然后每次调用从池中去取一个实例。xmlhttp实例通讯完毕后我们不用做任何处置,因为它自身的readyState属性可以标识出它是否可用,如果当时没有空闲的xmlhttp实例,且池中的实例数小于最大实例个数,那么就创建一个新的实例并放入池中。重新改进的实现代码如下:
复制代码代码如下:

//封装XMLHTTP的MyAjaxObj类
varMyAjaxObj=newObject();
varmaxXmlHttpCount=5;//最多5个xmlhttp对象存在

MyAjaxObj.reqList=[];//可以清空里面的项

MyAjaxObj.getFreeObj=function(){
varreq=null;
varlen=this.reqList.length;
//先从当前的池里取
for(vari=0;i<len;i++){
if(this.reqList[i]){
if(this.reqList[i].readyState==4||this.reqList[i].readyState==0){
req=this.reqList[i];
break;
}
}
}
//如果没有闲置的对象,自己独立创建
if(req==null){
if(this.reqList.length<maxXmlHttpCount){
req=getXmlHttp();
this.reqList.push(req);
}
}
returnreq;
}


//创建一个XMLHTTP对象,兼容不同的浏览器
functiongetXmlHttp(){
varxmlHttp=false;
vararrSignatures=["MSXML2.XMLHTTP.5.0","MSXML2.XMLHTTP.4.0",
"MSXML2.XMLHTTP.3.0","MSXML2.XMLHTTP",
"Microsoft.XMLHTTP"];
for(vari=0;i<arrSignatures.length;i++){
try{
xmlHttp=newActiveXObject(arrSignatures[i]);
returnxmlHttp;
}
catch(oError){
xmlHttp=false;//ignore
}
}
//thrownewError("MSXMLisnotinstalledonyoursystem.");
if(!xmlHttp&&typeofXMLHttpRequest!="undefined"){
xmlHttp=newXMLHttpRequest();
}
returnxmlHttp;
}

/*封装XMLHTTP向服务器发送请求的操作
url:向服务器请求的路径;method:请求的方法,即是get/post;***callback:当服务器成功返回结果时,调用的函数(类似c#回调函数)***
data:向服务器请求时附带的数据;urlencoded:url是否编码;cached:是否使用缓存;callBackError;当服务器返回错误时调用的函数
*/
MyAjaxObj.send=function(url,method,callback,data,urlencoded,cached,callBackError){
varreq=this.getFreeObj();//从池里或者直接实例化一个XMLHTTP的实例

//当XMLHTTP的请求状态发生改变时调用(核心处理函数)
req.onreadystatechange=function(){
//当请求已经加载

if(req.readyState==4){
//当请求返回成功
if(req.status==200){//或者req.status<400
//当定义了成功回调函数时,执行成功回调函数
if(callback)
callback(req,data);
}
//当请求返回错误

else{
//当定义了失败回调函数时,执行失败回调函数
if(callBackError)
callBackError(req,data);
}

//有池的管理,我们可以省却释放资源的方法
//try{
//deletereq;
//req=null;
//}
//catch(e){
//alert(e.message);
//}
}
}

//如果以POST方式回发服务器
if(method.toUpperCase()=="POST"){
req.open("POST",url,true);
//请求是否需要缓存(只有在req.open之后才可以设置此项)
if(cached)
req.setRequestHeader("If-Modified-Since","0");
//请求需要编码
if(urlencoded)
req.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
req.send(data);
MyAjaxObj.reqList.push(req);
}
//以GET方式请求
else{
req.open("GET",url,true);
//请求是否需要缓存
if(cached)
req.setRequestHeader("If-Modified-Since","0");
req.send(null);
MyAjaxObj.reqList.push(req);
}
returnreq;
}

//全部清除XMLHTTP数组元素,释放资源
MyAjaxObj.clearReqList=function(){
varlen=MyAjaxObj.reqList.length;
for(vari=0;i<len;i++){
varreq=MyAjaxObj.reqList[i];
if(req){
try{
deletereq;
}catch(e){}
}
}
MyAjaxObj.reqList=[];
}

//进一步封装XMLHTTP以POST方式发送请求时的代码
//isClear:是否清除XMLHTTP数组的所有元素;其他参数的意义见MyAjaxObj.send
MyAjaxObj.sendPost=function(url,data,callback,isClear,isCached,callBackError){
if(isClear){
MyAjaxObj.clearReqList();
}
MyAjaxObj.send(url,"POST",callback,data,true,isCached,callBackError);//post方法需要编码
}
//进一步封装XMLHTTP以GET方式发送请求时的代码
MyAjaxObj.sendGet=function(url,args,callback,isClear,isCached,callBackError){
if(isClear)
MyAjaxObj.clearReqList();
returnMyAjaxObj.send(url,"GET",callback,args,false,isCached,callBackError);
}

最后再ps:上周周末和一个哥们聊天的时候谈到ajax应用中的xmlhttp对象。那哥们ms很“虔诚”地问我说xmlhttp怎么就异步通信了。我当时竟然毫不思索地说因为这个对象处理我们的请求调用是“异步”的(当然可以设置成同步的,不过这是一句废话),当前这个请求不会影响其他的操作。这个回答是很“官方”的,显然没有说到问题的本质。哥们,您的眼神儿有必要那么bs人么?现在稍作分析,个人认为其实每个xmlhttp异步请求都会触发一个回调函数,这个回调函数的调用不影响其他的操作,这个方法才是“异步”。如果对比c#里的异步处理回调方法,它们在原理上其实是相通的。哈哈,现在终于想通了,真是太骄傲,太有出息了,想到就兴奋!