论坛首页 Web前端技术论坛

具有xhr对象管理功能的Ajax简易封装(Majax)

浏览 5175 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2007-07-20  
内部由一个数组缓存工作中的xhr对象,类似于“池”,当一个请求发生时,由池中首个空闲的xhr对象执行相关操作,当请求处理完毕后,对象被回收。

这在网络速度无法保证、服务器端响应较慢,而Ajax采用异步方式时很有用。外部可以把一个Majax实例当作具有自动缓冲机制并持久有效的异步通讯对象看待。

使用接口简单并且灵活,回调函数接口也十分友好。详细内容可参看源码中的注释,希望大家喜欢。

用法:
<script language="javascript" src="majax.js"></script>
<script language="javascript">
function callback(req, id) {
    // 直接使用
    document.getElementById(id).innerHTML = req.responseText;
}
var _mObj = new Majax();
</script>
<div id="someid"></div>
<div onClick="_mObj.get('/yourscript.php?name=xxx', callback, 'someid')">GET方式</div>
<div onClick="_mObj.post('/yourscript.php', 'name=xxx', callback, 'someid')">POST方式</div>


提示:回调函数中的第二个参数可以传递任意类型的数据,所以可以在异步设计的时候用于协调一些状态。使用中如果发现Bug,欢迎在此留言或Email:tubz@21cn.com

接口示例(假如已 var _mObj = new Majax();):
//-- 普通接口 -----------------------------------------------------------------

// GET方式请求。
// (URL, 回调函数, 传递给回调函数的附加数据, 是否异步)
_mObj.get(url, callback, fd, asyn)

// POST方式请求,Post-data仅为文本。
// (URL, POST数据, 回调函数, 传递给回调函数的附加数据, 是否异步)
_mObj.post(url, data, callback, fd, asyn)

//-- 低阶接口 -----------------------------------------------------------------

// 复位/设置请求。
// (URL, [GET|POST]方法, 是否异步)
_mObj.reset(url, method, asyn)

// 设置请求头信息。
_mObj.header(name, value)

// 发送请求(若reset时为GET,data为null)。
// (发送数据, 回调函数, 传递给回调函数的附加数据)
_mObj.send(data, callback, fd)

// 设置出错处理函数
// func(req, callback)
_mObj.e_handler(func)


压缩包内文件说明:
  majax.js 用jsmin压缩过的纯代码,实际引用文件;
  majax_.js 书写时的源代码,含注释;
  test.html/servdt.php 测试用文件。
  • majax_v0.1.rar (3.5 KB)
  • 描述: 带请求对象池管理功能的Ajax封装,接口兼顾灵活与简便。
  • 下载次数: 46
  • majax_v0.2.rar (4.2 KB)
  • 描述: 增加了出错处理接口,修复出错时xhr对象无法回收的问题。
  • 下载次数: 107
   发表时间:2007-07-21  
1. 反复利用同一个xhr在某些平台上可能有问题。
2. 我个人认为xhr没有必要用池。除非你有足够证据证明创建xhr是很消耗资源的。
0 请登录后投票
   发表时间:2007-07-23  
确实,我不清楚xhr对象在每个浏览器实现中的开销,但是如果池的实现也很高效的话,用池就是值得的。
源码是LGPL的(很简单的东西,其实基本上都谈不上什么版权之类的),如果你看源码,会发现这点。
当然欢迎你进一步优化它并共享一哈,呵呵。

>>反复利用同一个xhr在某些平台上可能有问题。
请教会在什么平台什么情况下有问题?
当一个对象被重用的时候,会被open重新初始化的,并且只有当回调函数执行完之后,对象才会被回收。
0 请登录后投票
   发表时间:2007-07-23  
池增加了代码复杂度,反而可能降低效率。我估计,native的new XMLHttpRequest肯定应比你的池要高效。只有IE6,因为是创建一个AcitveX对象,可能较为低效。但是这种效率提高到底有多少?非常值得怀疑。

事实上,对象池技术在多数场合并无必要,例如在java中,只有重量级资源对象,或者反复创建相同的对象并可能影响性能,才会使用对象池。

而在js里面:
1. js对象只是XHR的wrapper,纯粹new一个js对象的开销不会比你复杂的池要大,只会小。
2. XHR自己可能存在优化。实际上,UA自己或者更底层的网络协议层,对于http请求都是有队列的。所以不用你画蛇添足。
3. 就算要用池,浏览器同源请求在同一时刻只能有2个,不同源的也有一定上限(通常10个以下),所以你真的要做池的话,其实应该控制上限。

总之,XHR的池是毫无意义的——除非你有数据证明它确实提高了效率。

BTW,使用你这个代码的“好处”是,虽然你的这个代码在IE6上会有内存泄漏,但同样是泄漏,因为你重复利用了XHR对象,所以估计你的泄漏量会小。
0 请登录后投票
   发表时间:2007-07-28  
新创建一个xhr对象的开销有多大我不清楚,但是在实际应用中必须顾及浏览器的兼容性,所以创建一个xhr对象其实是需要一些代码的,比如:
function new_object()
{
    var A;
    var _msxmlhttp = new Array(
        'Msxml2.XMLHTTP.6.0',
        //'Msxml2.XMLHTTP.5.0',
        //'Msxml2.XMLHTTP.4.0',
        'Msxml2.XMLHTTP.3.0',
        'Msxml2.XMLHTTP',
        'Microsoft.XMLHTTP');
    for(var i = 0; i < _msxmlhttp.length; i++) {
        try {
            if(A = new ActiveXObject(_msxmlhttp[i])) break;
        } catch (e) {
            A = null;
        }
    }
    if(!A && typeof XMLHttpRequest != "undefined")
        A = new XMLHttpRequest();
    if(!A)
        alert("Could not create connection object.");

    return A;
}


但是,如果创建的对象被保留下来,在可以安全使用的前提下,返回一个现成的对象肯定要比新创建一个兼容对象快不少。对于池的复杂性,封装就是为了掩盖复杂性的,用户只需要面对接口。(白:其实代码并不复杂)

在一个页面存在大量Ajax请求的应用里,从消耗累加的角度看,用这个封装明显比每次都创建一个新的xhr要高效和节约。并且由于重复使用xhr对象,还可缓解hax所说的IE6存在的内存泄漏问题。

比较简单的东西……到此打住。
0 请登录后投票
   发表时间:2007-07-28  
Liner 写道
新创建一个xhr对象的开销有多大我不清楚,但是在实际应用中必须顾及浏览器的兼容性,所以创建一个xhr对象其实是需要一些代码的,比如:

但是,如果创建的对象被保留下来,在可以安全使用的前提下,返回一个现成的对象肯定要比新创建一个兼容对象快不少。对于池的复杂性,封装就是为了掩盖复杂性的,用户只需要面对接口。(白:其实代码并不复杂)

在一个页面存在大量Ajax请求的应用里,从消耗累加的角度看,用这个封装明显比每次都创建一个新的xhr要高效和节约。并且由于重复使用xhr对象,还可缓解hax所说的IE6存在的内存泄漏问题。

比较简单的东西……到此打住。


1. 既然多大开销你不清楚,那就没有充分理由用池。因为你的池可能开销更大。
2. 创建一个xhr的兼容代码不需要那么复杂。对于支持native xhr的(ff,opera,safari,ie7),根本不需要任何额外代码;对于IE6及以前的,只需要初始的时候创建一个XMLHttpRequest函数,且该函数根本不用每次都循环try catch(这是一个基本的js编程,留给大家当作业吧)。
3. 不管你掩盖的如何,如果你掩盖的复杂性本身就是没有必要的,那就应该以剃刀原则去除之。
4. 前面还说你不知道开销多少,后面又说高效节约,不知道才过了两段文字,就哪里明显了?
5. 请你好好再读读我前面的帖子,看看我为什么说js对象池没有必要,以及就算要实现池你也没实现到位。
6. 关于泄漏,把我的揶揄之词当成你的理由,真令人哭笑不得。

所谓忠言逆耳,既然你不想听,那我也打住。
0 请登录后投票
   发表时间:2007-07-28  
引用

>> 补充:

1、请勿在回调函数和错误处理函数中抛出异常。


这点约束是非常不明智的。
0 请登录后投票
   发表时间:2007-07-28  
引用

所谓忠言逆耳,既然你不想听,那我也打住。

首先谢谢你的回复,讲解得很详细。(真心感谢,我很菜,所以希望能得到明白人的指点,最好是有代码说明)
我那个到此打住的意思希望不要被顶上去,影响别的好贴被下沉。
引用

6.关于泄漏,把我的揶揄之词当成你的理由,真令人哭笑不得。

因为在论坛上我不揶揄别人(除非是老朋友),所以没看出来。
引用

>>1、请勿在回调函数和错误处理函数中抛出异常。
这点约束是非常不明智的。

是的,如果要通用就该改一下。
我本来的想法是希望用户在回调函数或错误处理中就解决掉内层抛出的异常,不再往外发(设计上的强制,但未必可行)。

其实还有一个不足,就是异步时返回的xhr对象不能被滥用。这个引用对象在对应请求的回调函数执行完之后会被回收,所以再在其上操作其实是针对另一个请求的——除非那就是想要的,否则就错了。
我本来是不想提供返回,但为灵活性还是返回了。

………………………………………………………………………………………………………………………………………

如果需要取消上面“勿在回调函数和错误处理函数中抛出异常”的限制,可以用下面的代码替换压缩包中对应的函数。
Majax._callback = function(callback, data, its, obj)
{
    var _req = its[0];

    if(_req.readyState == 4) {
        try {
            if(_req.status != 200) {
                if(obj._eh) obj._eh(its[0], callback);
            }else{
                callback(_req, data);
            }
        } finally {
            its[1] = false;
        }
    }
}

不知道该如何捕获xhr异步调用回调函数时从回调函数中抛出的异常?我觉得不应该在这里捕获,应该放行异常继续向上,或许由浏览器显示那些“难看”的代码,呵呵。
0 请登录后投票
论坛首页 Web前端技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics