建一个XMLHttpRequest对象池

在ajax应用中,通常一个页面要同时发送多个请求,如果只有一个XMLHttpRequest对象,前面的请求还未完成,后面的就会把前面的覆盖掉,如果每次都创建一个新的XMLHttpRequest对象,也会造成浪费。解决的办法就是创建一个XMLHttpRequset的对象池,如果池里有空闲的对象,则使用此对象,否则将创建一个新的对象。

下面是我最近写的一个简单的类:

/** 
 * XMLHttpRequest Object Pool
 *  
 * @author    legend <legendsky@hotmail.com>
 * @link      http://www.ugia.cn/?p=85 
 * @Copyright www.ugia.cn  
 */ 

var XMLHttp = {
    
_objPool: [],
    
    
_getInstance: function ()
    {
        for (var 
0this._objPool.length++)
        {
            if (
this._objPool[i].readyState == || this._objPool[i].readyState == 4)
            {
                return 
this._objPool[i];
            }
        }
        
        
// IE5中不支持push方法
        
this._objPool[this._objPool.length] = this._createObj();

        return 
this._objPool[this._objPool.length 1];
    },

    
_createObj: function ()
    {
        if (
window.XMLHttpRequest)
        {
            var 
objXMLHttp = new XMLHttpRequest();

        }
        else
        {
            var 
MSXML = ['MSXML2.XMLHTTP.5.0''MSXML2.XMLHTTP.4.0''MSXML2.XMLHTTP.3.0''MSXML2.XMLHTTP''Microsoft.XMLHTTP'];
            for(var 
0MSXML.length++)
            {
                try
                {
                    var 
objXMLHttp = new ActiveXObject(MSXML[n]);        
                    break;
                }
                catch(
e)
                {
                }
            }
         }          
        
        
// mozilla某些版本没有readyState属性
        
if (objXMLHttp.readyState == null)
        {
            
objXMLHttp.readyState 0;

            
objXMLHttp.addEventListener("load", function ()
                {
                    
objXMLHttp.readyState 4;
                    
                    if (
typeof objXMLHttp.onreadystatechange == "function")
                    {
                        
objXMLHttp.onreadystatechange();
                    }
                },  
false);
        }

        return 
objXMLHttp;
    },
    
    
// 发送请求(方法[post,get], 地址, 数据, 回调函数)
    
sendReq: function (methodurldatacallback)
    {
        var 
objXMLHttp this._getInstance();

        
with(objXMLHttp)
        {
            try
            {
                
// 加随机数防止缓存
                
if (url.indexOf("?") > 0)
                {
                    
url += "&randnum=" Math.random();
                }
                else
                {
                    
url += "?randnum=" Math.random();
                }

                
open(methodurltrue);
                
                
// 设定请求编码方式
                
setRequestHeader('Content-Type''application/x-www-form-urlencoded; charset=UTF-8');
                
send(data);
                
onreadystatechange = function ()
                {                   
                    if (
objXMLHttp.readyState == && (objXMLHttp.status == 200 || objXMLHttp.status == 304))
                    {
                        
callback(objXMLHttp);
                    }
                }
            }
            catch(
e)
            {
                
alert(e);
            }
        }
    }
}; 

示例:

<script type="text/javascript" src="xmlhttp.js"></script>
<script type="text/javascript">
function test(obj)
{
    alert(obj.statusText);
}

XMLHttp.sendReq('GET', 'http://www.ugia.cn/wp-data/test.htm', '', test);
XMLHttp.sendReq('GET', 'http://www.ugia.cn/wp-data/test.htm', '', test);
XMLHttp.sendReq('GET', 'http://www.ugia.cn/wp-data/test.htm', '', test);
XMLHttp.sendReq('GET', 'http://www.ugia.cn/wp-data/test.htm', '', test);

alert('Pool length:' + XMLHttp._objPool.length);
</script> 

demo 下载xmlhttp.js

60 Comments »

  1. s5s5 said,

    December 22, 2005 @ 7:12 pm

    大哥哥,你的日志时间超前了吧,已经在BXNA显示了一天了。。。

  2. legend said,

    December 22, 2005 @ 7:19 pm

    我发现这个问题了,后台的时间选项改了改,没管用,帖子时间我也改了。郁闷

    再改,改到21号

  3. danielking said,

    December 23, 2005 @ 9:12 am

    怎么在IE下使用有问题呢?
    提示64行第5个字符,缺少标识符字符串或数字
    然后提示XMLHttp未定义

    在Firefox使用正常

  4. legend said,

    December 23, 2005 @ 9:39 am

    源代码里有中文的注释,是ansi的,如果你的网站或ie下选择编码为UTF-8,可能会导致错误,你把你ie的编码改成gb2312看看,或者去掉文件里的中文注释

  5. nickfan said,

    December 26, 2005 @ 10:48 am

    服务器是不是php5的?可能需要设置一下php.ini。

  6. andot said,

    December 27, 2005 @ 5:28 pm

    测试自动转向

  7. legend said,

    December 27, 2005 @ 5:31 pm

    测试自动转向

  8. andot said,

    December 27, 2005 @ 8:12 pm

    测试自动跳转

  9. 野马 said,

    December 29, 2005 @ 3:57 pm

    思路非常好,小弟在下提几个建议:
    1、“对象池”的管理功能需要加强,比如池的容量。
    2、“对象池”的内存回收需要加强,比如使用完毕的对象释放内存。
    3、请求最好序列一下,以控制由于服务器延时或网络延时导致的先请求的后得到结果。
    4、为了代码复用和健壮,回调函数应该验证是否有效,也就是回调函数应该可以为空(可以缺省)。

  10. legend said,

    December 31, 2005 @ 9:57 am

    谢谢“野马”的建议,有空再完善一下。IE默认有两个线程的限制,所以池的容量不需要很大。

  11. hzy said,

    December 31, 2005 @ 1:11 pm

    看了legend的代码,才知道啥叫高手。很想请教legend,这些mozilla和ie各自特性和差别的资料从何处得来?因为我花了2个多钟头才查到push和pop是ie5.5以后才有的;javascript中对象的构造O={:,:,:…}是javascript1.2里面就有的(因此这样写而不是用new object()或者function objectname(){}应该具有更好的兼容性);以及那个很有意思的addeventlistener是mozilla的DOM里面特有的。查到这些东东,我的文件夹里面已经堆满了dom,javascript的相关规范了,而且还是E文的,这多少让我有些灰心。还有几个问题,那个load是不是mozilla里面xmlhttprequest的事件?load对应readystate=4,那么还有没有0,1,2,3对应的其他事件?因为我在www.xmlhttp.cn上面没有找到这个信息,xmlhttprequest我在mozilla的DOM文档里面也没有找到。另外,那个“IE默认有两个线程的限制,所以池的容量不需要很大”这句不太明白。
    感谢你的这些文章和代码,如果能够解答我的这些疑问的话,就更感谢了,呵呵。
    敬佩!

  12. hzy said,

    December 31, 2005 @ 2:09 pm

    PS, “Content-Type=application/x-www-form-urlencoded; charset=UTF-8″是给服务器看的,xmlhttprequest并不会因此去编码data中的数据,因此data被send之前,需要手工编码。我在IE下面用post试了一下,自己构造了一个form表单在http请求中的形式name1=value1&name2=value2,如果不事先编码的话,value中如果有“?”或者汉字之类的字符,就会导致出错。对于get也有类似的问题。IE下面有encodeURI等几个函数用来对字符串编码,可以解决这个问题,但这需要浏览器版本IE5.5以上(尽管encodeURI系列是ECMAScript标准)。我找到了一个可以进行url编码的脚本,但仅仅是那个unicode和gb2312的对应数组,就一百多K。
    想请教legend,是否有比较好的通用的解决方法?谢谢。

  13. legend said,

    December 31, 2005 @ 2:52 pm

    回答hzy:一些浏览器方面的差别是我在以前做东西的时候遇到的,所以后面写代码的时候可以去避免这些问题。addeventlistener这个是参考webfx上的一些代码。至于mozilla中xmlhttprequest里的事件,新版本中已经不存在这样的问题了,老版本未测试。
    IE默认同时向一个站点发起的请求是两个,这个问题是我在做上传程序的时候遇到的,因为我同时向服务器发送三个请求,但最后一个一直得不到回应,只有等到前面两个结束后才能返回结果来。
    至于urlencode这个在js里面用encodeURIComponent这个函数,各种浏览器都可以的。“Content-Type=application/x-www-form-urlencoded; charset=UTF-8"这句话是告诉服务器,我发送的数据是urlencode过的。

  14. hzy said,

    December 31, 2005 @ 3:32 pm

    encodeURIComponent在IE5.0里面没有,文档上这么说的,我没试过,所以结论下得比较武断。谢谢你耐心细致的解答。另外再跟你套个近乎,俺也是山东的。山东济南人。呵呵。现在在青岛读研,也是26岁。呵呵。刚才好好看了你的blog一下发现了很多好东东,那个bindow,里面的图表功能很有意思,不过估计只能在IE下面运行(vml)?
    今天很高兴,知道我有一个这么厉害的老乡。赞一个!

  15. hzy said,

    January 12, 2006 @ 12:04 pm

    你好,本来想直接copy你的生成xmlhttp对象的代码,发现有点问题。
    在IE下面也可以手工给window添加名为XmlHttpRequest的属性,如果用户代码中恰好有这么一个自定义的属性,这段代码就不能返回正确的对象了。也许就正如你所说,代码还有可以完善的地方。
    PS,看你的代码有种很high的感觉,自由而不放浪,英气逼人,呵呵。

  16. FindRain said,

    January 16, 2006 @ 10:29 am

    有一个问题,是否可以给每个请求指定超时时间,加上超时处理?

  17. mincyw said,

    January 17, 2006 @ 7:12 pm

    非常感谢,你的东东帮了我很大的忙!

  18. maltose said,

    January 19, 2006 @ 8:29 pm

    我想请教一个关于http://www.yule21.com/info/990.htm
    这篇文章说得这个问题,他是用vbscript解决的
    我想请问一下用javascript就一定没有办法解决了吗?
    盼望答案

  19. longbill said,

    April 23, 2006 @ 7:50 pm

    为什么blog文章的标题不能复制呢?奇怪

  20. Huangl said,

    April 29, 2006 @ 12:46 am

    为什么每次创建一个xmlHttprequest对象的代价需要考虑呢?即使浪费,不也是浪费clint端的那一点“小小”的性能么?对整个系统的性能会造成影响么?作者是否做过性能上的测试,或者有一些经验数据可以公布一下么?

  21. legend said,

    May 10, 2006 @ 1:30 am

    没有测试过也没有经验数据,只是认为ie每次创建activex对象应该是有些花销的。我这篇文章的主要目的并不是为了节能,而是为了并发。

  22. Huangl said,

    May 10, 2006 @ 1:59 am

    ??不创建一个池,就不能并发了么?
    还有,xmlhttprequest对象的生命周期有多长?每次从池中取出一个用就可以么?
    不好意思,新手,不明白的太多,呵呵。

  23. legend said,

    May 10, 2006 @ 2:06 am

    不创建也可以并发,但每次得创建一个新的xmlhttprequest对象。我创建池的目的,就是为了能够重复利用已经创建的对象。

    说到并发,ie默认是每个站点同时只允许两个线程的。

    这篇文章现在看来,还是有很多不妥的地方。

  24. nada said,

    May 12, 2006 @ 7:34 pm

    真高手,向你学习,顶一个。

  25. Zhang-Zi said,

    May 17, 2006 @ 3:12 am

    这东西不错。那个IE的Ajax缓存情况以前我遇到过,弄了我好久,到后来才发现IE的ajax会缓存。要是早看到你这篇文章就好了

  26. An said,

    June 6, 2006 @ 7:22 am

    一定要说声感谢!

  27. diaodiao said,

    November 5, 2006 @ 5:43 pm

    用你的代码在本地运行的时候就出现了状态代码是4 的时候回调函数没反应的情况,这个是怎么回事?

  28. diaodiao said,

    November 5, 2006 @ 8:08 pm

    o~~ 试验成功了,之前不知道是哪里搞错了,多谢多谢,救急了

  29. 海南马自达 said,

    December 13, 2006 @ 3:05 pm

    非常感谢

  30. Alan said,

    December 31, 2006 @ 11:31 am

    思路很好,不过有个问题,IE 解释脚本的时候是顺序执行的,这就是说,他会沿你设计的脚本一步一步走下去! 而 xmlhttpRequst 则是个异步过程,这样,当下一步脚本调用前,xmlhttpResquest 总是还没有send,所以这个线程池最后也没起到作用,调用1次sendReq就多创建一个xmlHttpRequest,和没用池子几乎没什么差别

  31. legend said,

    December 31, 2006 @ 1:02 pm

    調用xmlhttprequest就發送了,然後下一次調用的時候,如果前面的都在使用中,會自動創建一個新xmlhttp對象。如果有空閒的對象才會直接使用它。

    這個池子並不是爲了效率,而是如果是單一的xmlhttprequest對象,重復調用的話,如果前一個正在發送,後面的就會覆蓋這個對象,那我們的請求就丟失了。

  32. streetsmart said,

    January 12, 2007 @ 3:03 am

    谢谢您,您给了很大帮助。

  33. kevin said,

    April 21, 2007 @ 6:55 pm

    使用中发现了一个问题。当我读取A完毕,并正确显示之后,点B,读取B的内容的时候,B可以正确显示,而A又会重新进入读取状态,而且始终无法完成,即staut始终=0。这是什么呢?怎么解决?

  34. kevin said,

    April 21, 2007 @ 6:59 pm

    我代码做过改动。改动如下:(注:showid是传入的值,每次都不一样,就是显示的地方。)
    onreadystatechange = function ()
    {
    if (objXMLHttp.readyState “;
    }
    if (objXMLHttp.readyState == 4 && (objXMLHttp.status == 200 || objXMLHttp.status == 304))
    {
    var response = objXMLHttp.responseText;
    document.getElementById(showid).innerHTML=response;

  35. legend said,

    April 21, 2007 @ 8:28 pm

    要不你就用这个吧: http://www.ugia.cn/?p=122

  36. huxishengming said,

    May 5, 2007 @ 3:58 pm

    objXMLHttp.readyState = 0;
    在ff中这样为对象添加一个属性可以吗?不是应该用addAttribute吗?

  37. zeroone said,

    May 12, 2007 @ 12:08 pm

    加入随机数怎么还是没有办法解决IE的缓存
    我用
    xmlHttp.abort();
    解决了

  38. 毛毛虫 said,

    May 22, 2007 @ 9:08 am

    ???10)uuu(0)iii(0)ooo(0)000(0)0i(0)0889(0)45677(0)0gk(0)hh(0)u(0)p(0);(0)
    ie下 请求页面得到的数据会出现如上的乱码 导致页面布局都乱了 请问这是怎么回事啊 xmlhttp.js里的中文注释我已经去掉了
    ff下一切正常

  39. legend said,

    May 22, 2007 @ 9:19 am

    你页面 编码是什么?

  40. 毛毛虫 said,

    May 22, 2007 @ 9:26 am

    html:

    New Document

    js:
    setRequestHeader(‘Content-Type’, ‘application/x-www-form-urlencoded; charset=gb2312′);
    send(data);
    onreadystatechange = function ()
    {
    if (objXMLHttp.readyState == 4 && (objXMLHttp.status == 200 || objXMLHttp.status == 304))
    {
    //callback(objXMLHttp);
    alert(objXMLHttp.responseText);
    }
    }
    server端:asp

  41. 毛毛虫 said,

    May 22, 2007 @ 9:27 am

    server端:asp

  42. 毛毛虫 said,

    May 22, 2007 @ 9:28 am

    啊 不让发代码啊
    server端 asp:
    response.charset = “gb2312″

  43. 毛毛虫 said,

    May 22, 2007 @ 9:30 am

    客户端只是发送了一个请求页面 还没参数
    var u2 = “txlload/load_team_list.asp”;
    XMLHttp.sendReq(‘GET’,u2,”,callback); //打开页面时 加载分组

  44. 毛毛虫 said,

    May 22, 2007 @ 9:48 am

    问题找到了 是创建的xmlhttprequest对象问题
    我改成这样了:
    if(window.XMLHttpRequest){
    objXMLHttp = new XMLHttpRequest();
    if (objXMLHttp.overrideMimeType) {
    objXMLHttp.overrideMimeType(“text/xml”);
    }
    }
    else if (window.ActiveXObject){
    try {
    objXMLHttp = new ActiveXObject(“Msxml2.XMLHTTP”);
    } catch (e) {
    try {
    objXMLHttp = new ActiveXObject(“Microsoft.XMLHTTP”);
    } catch (e) {}
    }
    }
    if (!objXMLHttp) {
    window.alert(“can’t create XMLHttpRequest object.”);
    return null;
    }
    ie下也正常了 不过不知道是什么原因造成的

  45. Jeffy said,

    August 31, 2007 @ 10:40 am

    我比较支持用json,因为rpc有性能问题
    作者能告诉一下我QQ和MSN吗?
    UGiA PHP UPLOADER 怎么实现远程上传?我意思是说我网站在A服务器,在A服务器页面上操作时,怎么把文件上传到B服务器上!

  46. Jeffy said,

    August 31, 2007 @ 10:42 am

    上面发错地方了,应该发在 phprpc 那个里面

  47. hongyu said,

    August 31, 2007 @ 10:52 am

    写得真好,正想研究下并发的xhr呢,学习了,文档注释也很全,难得啊!

  48. 胡杨 said,

    October 24, 2007 @ 8:34 pm

    能还能逐行的解释一下。
    刚刚接触xmlhttprequest这方面的知识。
    切盼
    我的email:micenote@yahoo.com.cn

  49. irene said,

    December 12, 2007 @ 2:17 pm

    正好遇到这种问题,需要解决。这个方法很好用!

  50. 破曉之陽 said,

    December 28, 2007 @ 12:33 am

    其實在IE7.0 里面。
    if (window.XMLHttpRequest)
    {
    var objXMLHttp = new XMLHttpRequest();
    }
    如果把 var objXMLHttp = new XMLHttpRequest();

    //var objXMLHttp=new ActiveXObject(“Microsoft.XMLhttp”); 也是可行的。就是說。在IE7.0 里面。你先創建那個他就用那個。
    還有一個問題。就是當我們創建的是var objXMLHttp=new ActiveXObject(“Microsoft.XMLhttp”); 這個時候。responseText 這個東西可以用responsetext 就是說大小寫都可以的。
    但是如果是var objXMLHttp = new XMLHttpRequest(); 就必須是responseText。。。。 今天我就是給這個搞了好長時間。郁悶死了。

  51. qushui said,

    February 1, 2008 @ 11:38 am

    写得好,太方便了。谢谢。

  52. Liang said,

    August 12, 2008 @ 2:05 am

    个人觉得,这个池没什么用,只是省了NEW,但没什么用啊,取的时候得循环判断,不如直接new一个,然后读完数据后,也就是xmlhttprequest instance.readyState = 4的时候,清除IE占的内存,
    具体代码:

    if (!window.XMLHttpRequest) {
    window.XMLHttpRequest=function (){
    var http_request;
    try {
    http_request = new ActiveXObject(“Msxml2.XMLHTTP”);
    } catch (e) {
    try {
    http_request = new ActiveXObject(“Microsoft.XMLHTTP”);
    } catch (e) {}
    }
    return http_request;
    }
    }

    var loader = new XMLHttpRequest;
    var url = “HTMLPage2.htm”;// + “?tm=” + Math.random();

    loader.open(“get”,url ,true);

    loader.onreadystatechange=function()
    {
    if (loader.readyState == 1)
    {con.innerHTML=”loading………”; }
    if (loader.readyState==4)
    {
    con.innerHTML=loader.responseText;
    loader = null;//对象引用失效
    url = null;
    CollectGarbage();//清除在IE中占的内存
    }
    }
    //loader.setRequestHeader(‘Content-Type’, ‘application/x-www-form-urlencoded; charset=UTF-8′);
    loader.send(null);

    有什么事可以QQ交流:QQ:68049311

  53. rains.cn said,

    December 21, 2008 @ 12:12 pm

    提个小bug.
    当uri以问号开头的时候
    // 加随机数防止缓存
    if (url.indexOf(“?”) > 0)
    这里会判断失误
    我改成了
    if(url.match(/\?/))

  54. jeftom said,

    April 28, 2009 @ 11:14 pm

    “在ajax应用中,通常一个页面要同时发送多个请求,如果只有一个XMLHttpRequest对象,前面的请求还未完成,后面的就会把前面的覆盖掉,如果每次都创建一个新的XMLHttpRequest对象,也会造成浪费。”

    这一句话和《深入浅出ajax》一书33页中的句子一模一样。不知道是不是博主写的书?

  55. legend said,

    April 29, 2009 @ 2:28 pm

    当然不是,没有看过这本书。

  56. 韩苗 said,

    April 30, 2009 @ 9:53 pm

    你好,我的一个用来学习的项目中,要在加载页面的同时发出三个请求,我使用了你的对象池,效果很不错,其中调用时共有四个参数,第一个参数是GET或 POST,传递数据的方式,第二个参数是发出请求的URL,第三个参数是将要传递到服务器上的数据,第四个参数是执行完后返回页面要执行的一个函数。我在看完你写的例子之后,还有一点不明白的是,第三个参数如果要使用,应该怎么用呢?可否指点一二,谢谢!

  57. Jeff said,

    June 12, 2009 @ 10:50 am

    我是初学的。想问下一个页面多请求异步处理怎么用这个方法。
    谢谢了。能否给个实例参考一下。非常感谢。。

  58. 宇博 said,

    January 17, 2010 @ 6:28 pm

    自从使用了Jquery,这些问题都迎刃而解了

  59. 玉花香 said,

    April 19, 2010 @ 3:12 pm

    为什么我的老提示 [Object Error] 啊?

  60. www.tengbo558.com said,

    December 21, 2015 @ 10:39 pm

    成功需要成本,时间也是一种成本,对时间的珍惜就是对成本的节约。

RSS feed for comments on this post

Leave a Comment