分享

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

 douli 2005-07-23

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);
    }
  }
});

[Edit on 2005-07-06 17:46:10 By 泽欣(醒来)]

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多