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

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

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

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

MyAjaxObj.getFreeObj 
=   function () {
    
var  req  =   null ;
    
var  len  =   this .reqList.length;
    
// 先从当前的池里取
     for  ( var  i  =   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);
        }
    }
    
return  req;
}


// 创建一个XMLHTTP对象,兼容不同的浏览器
function  getXmlHttp() {
    
var  xmlHttp  =   false ;
    
var  arrSignatures  =  [ " MSXML2.XMLHTTP.5.0 " " MSXML2.XMLHTTP.4.0 " ,
                         
" MSXML2.XMLHTTP.3.0 " " MSXML2.XMLHTTP " ,
                         
" Microsoft.XMLHTTP " ];
    
for  ( var  i  =   0 ; i  <  arrSignatures.length; i ++ ) {
        
try  {
            xmlHttp 
=   new  ActiveXObject(arrSignatures[i]);
            
return  xmlHttp;
        }
        
catch  (oError) {
            xmlHttp 
=   false // ignore
        }
    }
    
//  throw new Error("MSXML is not installed on your system."); 
     if  ( ! xmlHttp  &&   typeof  XMLHttpRequest  !=   ' undefined ' ) {
        xmlHttp 
=   new  XMLHttpRequest();
    }
    
return  xmlHttp;
}

/* 封装XMLHTTP向服务器发送请求的操作
url:向服务器请求的路径;method:请求的方法,即是get/post;***callback:当服务器成功返回结果时,调用的函数(类似c#回调函数)***
data:向服务器请求时附带的数据;urlencoded:url是否编码;cached:是否使用缓存; callBackError;当服务器返回错误时调用的函数 
*/
MyAjaxObj.send 
=   function (url, method, callback, data, urlencoded, cached, callBackError) {
    
var  req  =   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 {
             //                 delete req;
             //                 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);
    }
    
return  req;
}

// 全部清除XMLHTTP数组元素,释放资源
MyAjaxObj.clearReqList  =   function () {
    
var  len  =  MyAjaxObj.reqList.length;
    
for  ( var  i  =   0 ; i  <  len; i ++ ) {
        
var  req  =  MyAjaxObj.reqList[i];
        
if  (req) {
            
try  {
                
delete  req;
            } 
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();
    
return  MyAjaxObj.send(url,  " GET " , callback, args,  false , isCached, callBackError);
}

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值