[转帖]Mootools源码分析-33 -- Request

原帖地址:http://space.flash8.net/space/?18713/viewspace-406767.html

原作者:我佛山人

 

var  Request  =   new  Class({
    
// 继承Chain,Events和Options的接口实现
    Implements: [Chain, Events, Options],

    options: {
        
/* onRequest: $empty, //开始事件
        onSuccess: $empty,  //成功事件
        onFailure: $empty,  //失败事件
        onException: $empty,
*/   // 异常事件
        url:  '' ,     // Ajax请求的地址
        data:  '' ,     // Ajax提交的地址
        headers: {     // Ajax请求的HTTP头数据
             // 来源信息
             ' X-Requested-With ' ' XMLHttpRequest ' ,
            
// 接受的内容类型
             ' Accept ' ' text/javascrīpt, text/html, application/xml, text/xml, */* '
        },
        
// 是否异步请求
        async:  true ,
        
// 提交方式
        method:  ' post ' ,
        
// 多次请求冲突时的处理方式
        link:  ' ignore ' ,
        
// 判断状态成功的方法
        isSuccess:  null ,
        
// 判断状态成功的方法
        emulation:  true ,
        
// 是否使用url编码
        urlEncoded:  true ,
        
// POST请求时使用的编码
        encoding:  ' utf-8 ' ,
        
// 动态执行字符脚本
        evalscrīpts:  false ,
        
// 动态执行返回字符脚本
        evalResponse:  false
    },

    
// 构造函数
    initialize:  function (options)    {
        
// 使用浏览器特性创建一个XmlHttpRequest对象
         this .xhr  =   new  Browser.Request();
        
this .setOptions(options);
        
// 判断状态成功的方法,如果参数中不提供,使用默认方法
         this .options.isSuccess  =   this .options.isSuccess  ||   this .isSuccess;
        
this .headers  =   new  Hash( this .options.headers);
    },

    onStateChange: 
function ()    {
        
// 如果状态码不等于4或者没有正执行的请求,直接返回
         if  ( this .xhr.readyState  !=   4   ||   ! this .running)     return ;
        
// 设置标记
         this .running  =   false ;
        
// 初始化状态码
         this .status  =   0 ;
        
// 设置状态码
        $ try ( function ()    {
            
this .status  =   this .xhr.status;
        }.bind(
this ));
        
// 如果状态码显示请求成功
         if  ( this .options.isSuccess.call( this this .status))    {
            
// 提取响应数据
             this .response  =  {text:  this .xhr.responseText, xml:  this .xhr.responseXML};
            
// 请求成功
             this .success( this .response.text,  this .response.xml);
        }    
else     {
            
// 响应数据全为null
             this .response  =  {text:  null , xml:  null };
            
// 请求失败
             this .failure();
        }
        
// 置空状态改变事件监听
         this .xhr.onreadystatechange  =  $empty;
    },

    
// 判断请求状态是否成功
    isSuccess:  function ()    {
        
// 状态码大于等于200小于300时为成功
         return  (( this .status  >=   200 &&  ( this .status  <   300 ));
    },

    
// 处理返回字符中包含的脚本
    processscrīpts:  function (text)    {
        
// 如果返回字符为纯脚本,直接解释执行
         if  ( this .options.evalResponse  ||  ( / (ecma|java)scrīpt / ).test( this .getHeader( ' Content-type ' )))     return  $exec(text);
        
// 混合字符时过滤出脚本,根据配置参数是否执行包含脚本
         return  text.stripscrīpts( this .options.evalscrīpts);
    },

    
// 请求成功
    success:  function (text, xml)    {
        
// 触发事件
         this .onSuccess( this .processscrīpts(text), xml);
    },

    
// 触发请求成功事件
    onSuccess:  function ()    {
        
// 同时触发请求完成和请求成功事件
         this .fireEvent( ' onComplete ' , arguments).fireEvent( ' onSuccess ' , arguments).callChain();
    },

    
// 请求失败
    failure:  function ()    {
        
// 触发事件
     this .onFailure();
    },

    
// 触发请求失败事件
    onFailure:  function ()    {
        
// 同时触发请求完成和请求失败事件
         this .fireEvent( ' onComplete ' ).fireEvent( ' onFailure ' this .xhr);
    },

    
// 设置请求的HTTP头部数据
    setHeader:  function (name, value)    {
        
this .headers.set(name, value);
        
return   this ;
    },

    
// 获取响应的HTTP头部数据
    getHeader:  function (name)    {
        
return  $ try ( function ()    {
            
return   this .xhr.getResponseHeader(name);
        }.bind(
this ));
    },

    
// 检查约束,类似Fx的同名方法
    check:  function ()    {
        
// 如果请求线程没有在运行中,返回真允许运行当前线程的请求
         if  ( ! this .running)     return   true ;
        
// 如果当前有正运行的请求线程
         switch  ( this .options.link)    {
        
// 配置了link参数为cancel时,直接取消正执行的线程,启用新线程
         case   ' cancel ' this .cancel();     return   true ;
        
// 等待当前线程执行完成再执行新线程
         case   ' chain ' this .chain( this .send.bind( this , arguments));     return   false ;
        }
        
return   false ;
    },

    
// 发送请求
    send:  function (options)    {
        
// 检查约束
         if  ( ! this .check(options))     return   this ;
        
// 设置标记
         this .running  =   true ;

        
// 根据参数类型处理
         var  type  =  $type(options);
        
if  (type  ==   ' string '   ||  type  ==   ' element ' ) options  =  {data: options};

        
// 实现更灵活的使用,可以将配置参数延后在send时
         var  old  =   this .options;
        options 
=  $extend({data: old.data, url: old.url, method: old.method}, options);
        
var  data  =  options.data, url  =  options.url, method  =  options.method;

        
// 不同类型的处理
         switch  ($type(data))    {
        
// 如果是HTML Element,读取它的值,并根据name值构成name=value的名值对
         case   ' element ' : data  =  $(data).toQueryString();  break ;
        
case   ' object ' case   ' hash ' : data  =  Hash.toQueryString(data);
        }

        
// put和delete提交方式时的处理,因为Ajax不支持put和delete,所以通过添加一个_method给后台处理
         if  ( this .options.emulation  &&  [ ' put ' ' delete ' ].contains(method))    {
            
var  _method  =   ' _method= '   +  method;
            data 
=  (data)  ?  _method  +   ' & '   +  data : _method;
            method 
=   ' post ' ;
        }

        
// POST方式指定编码时的处理,需要设置HTTP头部信息
         if  ( this .options.urlEncoded  &&  method  ==   ' post ' )    {
            
var  encoding  =  ( this .options.encoding)  ?   ' ; charset= '   +   this .options.encoding :  '' ;
            
this .headers.set( ' Content-type ' ' application/x-www-form-urlencoded '   +  encoding);
        }

        
// GET方式时的处理,直接将提交的数据加在请求地址后面
         if  (data  &&  method  ==   ' get ' )    {
            
// 判断请求地址中有否包含问号
            url  =  url  +  (url.contains( ' ? ' ?   ' & '  :  ' ? ' +  data;
            data 
=   null ;
        }

        
// 打开请求端口,注意以下代码中xhr对象的方法的执行顺序
         this .xhr.open(method.toUpperCase(), url,  this .options.async);

        
// 监听请求的响应状态更改事件
         this .xhr.onreadystatechange  =   this .onStateChange.bind( this );

        
// 设置所有HTTP头部信息
         this .headers.each( function (value, key)    {
            
if  ( ! $ try ( function ()    {
                
this .xhr.setRequestHeader(key, value);
                
return   true ;
                
// 出错时触发异常事件
            }.bind( this )))  this .fireEvent( ' onException ' , [key, value]);
        }, 
this );

        
// 触发onRequest事件
         this .fireEvent( ' onRequest ' );
        
// 发送数据
         this .xhr.send(data);
        
// 如果是同步执行,不需要事件监听,直接进到状态处理方法
         if  ( ! this .options.async)     this .onStateChange();
        
return   this ;
    },

    
// 取消请求
    cancel:  function ()    {
        
// 如果没有正运行的线程,不必操作,直接返回
         if  ( ! this .running)     return   this ;
        
// 设置标记
         this .running  =   false ;
        
// 中止请求
         this .xhr.abort();
        
// 置状态改变监听为空
         this .xhr.onreadystatechange  =  $empty;
        
// 创建新请求线程
         this .xhr  =   new  Browser.Request();
        
// 触发onCancel事件
         this .fireEvent( ' onCancel ' );
        
return   this ;
    }
});

// 就地执行的匿名函数
( function ()    {
    
// HTTP的方法处理
     var  methods  =  {};
    
// 处理用于Request继承实现的方法
    [ ' get ' ' post ' ' GET ' ' POST ' ' PUT ' ' DELETE ' ].each( function (method)    {
        methods[method] 
=   function ()    {
            
// 优先处理参数中字符类型的为请求地址,另一个有定义的参数为提交数据
             var  params  =  Array.link(arguments, {url: String.type, data: $defined});
            
// 最终仍需要通过调用send方法执行
             return   this .send($extend(params, {method: method.toLowerCase()}));
        };
    });
    
/*
    扩展实现,现在可以使用Request.get,Request.put之类的方法了,并且方法名不区分大小写,如:
    Request.get('http://wfsr.net/action.aspx', 'id=1');
    
*/
    Request.implement(methods);
})();

// 单件模式,根据Request为Element实现的扩展
Element.Properties.send  =  {
    
// setter
    set:  function (options)    {
        
// 先从临时对象取实例
         var  send  =   this .retrieve( ' send ' );
        
// 如果存在,取消执行
         if  (send) send.cancel();
        
// 删除缓存的Request实例,缓存配置参数
         return   this .eliminate( ' send ' ).store( ' send:options ' , $extend({
            data: 
this , link:  ' cancel ' , method:  this .get( ' method ' ||   ' post ' , url:  this .get( ' action ' )
        }, options));
    },

    
// getter
    get:  function (options)    {
        
// 如果提供了配置参数并且未存在实例
         if  (options  ||   ! this .retrieve( ' send ' ))    {
            
// 如果没有缓存配置参数,调用setter缓存
             if  (options  ||   ! this .retrieve( ' send:options ' ))     this .set( ' send ' , options);
            
// 根据缓存参数,缓存Request实例
             this .store( ' send ' new  Request( this .retrieve( ' send:options ' )));
        }
        
// 返回缓存中的实例
         return   this .retrieve( ' send ' );
    }
};

// Element的send方法
Element.implement({
    
// Element可以直接执行send方法实现Ajax请求了
    send:  function (url)    {
        
// 读取缓存中的Request实例
         var  sender  =   this .get( ' send ' );
        
// 发送请求,Request的配置参数需要单独设置
        sender.send({data:  this , url: url  ||  sender.options.url});
        
return   this ;
    }
});

 

转载于:https://www.cnblogs.com/maapaa/articles/mootools-s-33.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值