诊断并解决ajax异步调用产生的后遗症

       终所周知,在使用xmlHttpRequest进行异步调用时,浏览器会给每个请求分配一个独立线程(进程?没细去研究) ,当请求成功(或者失败后)再响应回调函数。当遇到某些ui部分的操作必须等在异步请求结束后才能进行的情况下,一般处理方式有两种:1、把界面部分的操作函数做为回调函数;2、改用同步模式。先来批判下第二种方法,这样无疑失去了ajax精髓的部分,所以不提倡。那么第一种方法呢?举个例子,对界面部分的操作写成了一个类,通过类的方法来进行调用,那此时,不得不把类的初始化,类的方法调用写到回调函数里。再举个例子,直接在这个类里编写实现异步调用的方法(也就是异步调用和ui操作是同一个类的不同方法)。虽然,这些都是普遍的做法,但是,这恰恰已经使界面操作和控制器部分混合在了一起,不符合mvc的思想,当然也并不利于重用。

       那如何来解决这个后遗症呢?设想下,问题是必须等到异步调用结束后,才能进行相应的其他操作,那么如果,设立一个独立的进程来检查异步调用是否已经结束,当结束后通知需要进行操作的方法再来执行。注意,这和用同步调用是有区别的。因为同步调用是阻塞了整个浏览器的进程。而这种用独立进程来检查的方式,并不影响其他异步调用。为此我对症下葯,实现了如下这个类:(需要prototype框架支持)

 

var  xRouter = Class.create();
xRouter
= {
    routers:[],     
/* 数组,用于存放请求 */
    
    
/* 注册请求,第一个参数为类实例或者函数引用,第二参数指示该请求的行为,是异步处理还是同步处理 */
    
/*
        如果请求是类,类中必须实现load方法,用来启动类的各种操作,并且如需要进行同步处理时,
        在适当的位置赋state字段为‘complete’,来指示此类已经调用结束。
    
*/
    register:
function (application,asy) {
        
if  ( ! asy) asy = false ;
        Object.extend(application,{$__asy:asy});
        
if  ( ! this .routers.include(application))
            
this .routers.push(application);
    },
    
    
/*
        注销请求,注意,请求必须是类的实例引用或者已声明函数的引用
    
*/     
    unregister:
function (application) {
        
this .routers = this .routers.without(Object.extend(application,{$__asy: true }));
        
this .routers = this .routers.without(Object.extend(application,{$__asy: false }));
    },
    
    
/*
        轮讯各个请求,实现各个请求的异步调用和同步调用
    
*/     
    dispatch:
function () {
        
this .routers.findAll( function (app){
                
return  (app.$__asy);
            }).each(
function (app) {
                
if  ( typeof  app == ' object ' )
                {
                    app.load();
                }
                
else   if ( typeof  app == ' function ' )
                {
                    app.call(
this );
                }
                
this .unregister(app);
            }.bind(
this ));
        
this .router();
    },

    
/* 内部函数,当注册的请求没有需要异步处理时,用户也可以直接调用此函数进行同步处理 */
    router:
function () {
        
if  ( this .routers.length > 0 )
        {
            
var  app = this .routers.shift();
            
if  ( typeof  app == ' function '   &&   ! app.$__asy)
            {
                app.call(
this );
                
this .router();
            }
            
else   if  ( typeof  app == ' object '   &&   ! app.$__asy)
            {
                app.load();
                app.base
= this ;                              /* 绑定this对象,以便其后调用 */
                setTimeout(
this .checkState.bind(app), 1 );    /* 用单独线程检查类的异步调用是否完成 */
            }
            
else
            {
                
this .router();
            }
        }
    },
    
    checkState:
function () {
        
if  ( this .state  &&   this .state.toLowerCase() == ' complete ' )
            
this .base.router();     /* 如果类的异步调用已经完成,则继续下一个需要同步处理的类或者函数 */
        
else
            setTimeout(
this .base.checkState.bind( this ), 1 );    /* 否则,继续检查 */
    }
};

 

 为了更加直观的理解此方法,下面再重新组织一下xmlHttpRequest(同样需要prototype框架支持)

 

var  xLoader = Class.create();
xLoader.prototype
= {
    initialize:
function (url,options) {
        
this .url = url;                  /* 请求后台模型或者页面的地址 */
        
this .options = Object.extend{
            {
                method:
' get ' ,
                parameters:
null
            }
            ,options 
||  {});           /* 用户自定义参数 */
        
this .loader = null ;              /* xmlHttpRequest请求加载实例 */
        
this .state = null ;               /* 类当前状态 */
        
this .isSuccess = false ;          /* 指示异步调用是否成功 */
        
this .request;                  /* 返回的request对象 */
    },
    
    
/* 类启动 */
    load:
function () {
        
var  url = jsEvent.noCache( this .url);    /* 一个防止页面缓存的处理函数,可以忽略 */
        
this .loader = new  Ajax.Request(
            url,
            {
                method:
this .options.method,
                parameters:
this .options.parameters,
                onSuccess:
this .successHandler.bind( this ),
                onFailure:
this .failureHandler.bind( this )
            }
        );
    },
    
    successHandler:
function (request) {
        
this .isSuccess = true ;
        
if  ( this .options.onSuccess)  this .options.onSuccess.call( this ,request);    /* 调用用户自定义的函数 */
        
this .completeHandler();
    },
    
    failureHandler:
function (request) {
        
this .isSuccess = false ;
        
if  ( this .options.onFailure)  this .options.onFailure.call( this ,request);    /* 调用用户自定义的函数 */
        
this .completeHandler();
    },
    
    completeHandler:
function (request) {
        
if  ( this .options.onComplete)  this .options.onComplete.call( this ,request);  /* 调用用户自定义的函数 */
        
this .request = request;                                                    
        
this .state = Ajax.Request.Events[ this .loader.transport.readyState];         /* 记录类的状态为complete */
    }
};

 

举例:

 

< script type = " text/javascript "  src = " lib/prototype-1.4.0.js " ></ script >   <!-- 需要prototype框架支持 -->
< script type = " text/javascript " >
// <![CDATA[
     var  xmlDoc;       
    
    window.onload
= function () {
        xRouter.register(
new  xLoader( ' test1.xml ' ,{onComplete:test1}), false );
        xRouter.register(
new  xLoader( ' test2.xml ' ,{onComplete:test2}), true );
        xRouter.register(test3,
true );
        xRouter.register(test4,
false );
        
/* 按照注册请求的顺序,处理其中需要同步处理的请求 */
        xRouter.dispatch();
    }
    
    
function  test1(request) {
        alert(
' 同步处理对test1.xml的异步请求 ' );
        xmlDoc
= request.responseXML;
    }
    
    
function  test2() {
        alert(
' 异步处理对test1.xml的异步请求 ' );
    }
    
    
function  test3() {
        alert(
' 异步处理test3函数 ' );
    }
    
    
var  test4 = Class.create();
    test4.prototype
= {
        initialize:
function () {
            alert(
' 同步处理对test1.xml异步请求结束后的test4类 ' );
            
this .state = null ;
        },
        
        load:
function () {
            alert(xmlDoc.xml);
            
this .state = ' complete ' ;
        }
    }
// ]]>
</ script >
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值