prototype 源码解读的第二部分 - Ajax.js

Ajax.js

/**
 * 定义 Ajax 对象, 静态方法 getTransport 方法返回一个 XMLHttp 对象
 
*/

var Ajax = {
  getTransport: 
function() {
    
return Try.these(
      
function() {return new ActiveXObject('Msxml2.XMLHTTP')},
      
function() {return new ActiveXObject('Microsoft.XMLHTTP')},
      
function() {return new XMLHttpRequest()}
    ) 
|| false;
  }
,
  
  emptyFunction: 
function() {}
}


/**
 * 我以为此时的Ajax对象起到命名空间的作用。
 * Ajax.Base 声明为一个基础对象类型
 * 注意 Ajax.Base 并没有使用 Class.create() 的方式来创建,我想是因为作者并不希望 Ajax.Base 被库使用者实例化。
 * 作者在其他对象类型的声明中,将会继承于它。
 * 就好像 java 中的私有抽象类
 
*/

Ajax.Base 
= function() {};
Ajax.Base.prototype 
= {
  
/**
   * extend (见prototype.js中的定义) 的用法真是让人耳目一新
   * options 首先设置默认属性,然后再 extend 参数对象,那么参数对象中也有同名的属性,那么就覆盖默认属性值。
   * 想想如果我写这样的实现,应该类似如下:
   setOptions: function(options) {
  this.options.methed = options.methed? options.methed : 'post';
  .
   }
   我想很多时候,java 限制了 js 的创意。
   
*/

  setOptions: 
function(options) {
    
this.options = {
      method:       'post',
      asynchronous: 
true,
      parameters:   ''
    }
.extend(options || {});
  }

}



/**
 * Ajax.Request 封装 XmlHttp 
 
*/
 
Ajax.Request 
= Class.create();

/**
 * 定义四种事件(状态), 参考http://msdn.microsoft.com/workshop/author/dhtml/reference/properties/readystate_1.asp
 
*/

Ajax.Request.Events 
= 
  ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];

/**
 * 
 
*/

Ajax.Request.prototype 
= (new Ajax.Base()).extend({
  initialize: 
function(url, options) {
    
this.transport = Ajax.getTransport();
    
this.setOptions(options);
  
    
try {
      
if (this.options.method == 'get')
        url 
+= '?+ this.options.parameters + '&_=';
    
   
/**
    * 此处好像强制使用了异步方式,而不是依照 this.options.asynchronous 的值
    
*/

      
this.transport.open(this.options.method, url, true);
      
   
/**
    * 这里提供了 XmlHttp 传输过程中每个步骤的回调函数
    
*/

      
if (this.options.asynchronous) {
        
this.transport.onreadystatechange = this.onStateChange.bind(this);
        setTimeout((
function() {this.respondToReadyState(1)}).bind(this), 10);
      }

              
      
this.transport.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
      
this.transport.setRequestHeader('X-Prototype-Version', Prototype.Version);

      
if (this.options.method == 'post') {
        
this.transport.setRequestHeader('Connection', 'close');
        
this.transport.setRequestHeader('Content-type',
          'application
/x-www-form-urlencoded');
      }

      
      
this.transport.send(this.options.method == 'post' ? 
        
this.options.parameters + '&_=' : null);
                      
    }
 catch (e) {
    }
    
  }
,
      
  onStateChange: 
function() {
    
var readyState = this.transport.readyState;
 
/**
  * 如果不是 Loading 状态,就调用回调函数
     
*/

    
if (readyState != 1)
      
this.respondToReadyState(this.transport.readyState);
  }
,
  
  
/**
   * 回调函数定义在 this.options 属性中,比如:
  var option = {
   onLoaded : function(req) {};
   
  }
  new Ajax.Request(url, option);
   
*/

  respondToReadyState: 
function(readyState) {
    
var event = Ajax.Request.Events[readyState];
    (
this.options['on' + event] || Ajax.emptyFunction)(this.transport);
  }

}
);

/**
 * Ajax.Updater 用于绑定一个html元素与 XmlHttp调用的返回值。类似与 buffalo 的 bind。
 * 如果 options 中有 insertion(from dom.js) 对象的话, insertion 能提供更多的插入控制。
 
*/

Ajax.Updater 
= Class.create();
Ajax.Updater.prototype 
= (new Ajax.Base()).extend({
  initialize: 
function(container, url, options) {
    
this.container = $(container);
    
this.setOptions(options);
  
    
if (this.options.asynchronous) {
      
this.onComplete = this.options.onComplete;
      
this.options.onComplete = this.updateContent.bind(this);
    }

    
    
this.request = new Ajax.Request(url, this.options);
    
    
if (!this.options.asynchronous)
      
this.updateContent();
  }
,
  
  updateContent: 
function() {
    
if (this.options.insertion) {
      
new this.options.insertion(this.container,
        
this.request.transport.responseText);
    }
 else {
      
this.container.innerHTML = this.request.transport.responseText;
    }


    
if (this.onComplete) {
      setTimeout((
function() {this.onComplete(this.request)}).bind(this), 10);
    }

  }

}
);
posted on 2006-03-25 18:47  jayu  阅读(247)  评论(0)    收藏  举报