`

Prototype1.5.1.1代码注释(二)

阅读更多
var Ajax = {
  getTransport: function() {
  /*之前定义的Try.these终于派上用场了*/
    return Try.these(
      function() {return new XMLHttpRequest()},
      function() {return new ActiveXObject('Msxml2.XMLHTTP')},
      function() {return new ActiveXObject('Microsoft.XMLHTTP')}
    ) || false;
  },

  /*用来统计活动的连接数*/
  activeRequestCount: 0
}

/*Ajax.Responders同样mixin了Enumerable对象*/
Ajax.Responders = {
  responders: [],

  _each: function(iterator) {
    this.responders._each(iterator);
  },

  /*注册一个responder,重复注册没有任何副作用*/
  /*参数为responder的名称*/
  register: function(responder) {
    if (!this.include(responder))
      this.responders.push(responder);
  },

  /*撤销注册*/
  /*参数为responder的名称*/
  unregister: function(responder) {
    this.responders = this.responders.without(responder);
  },

  /*遍历所有注册的responder,并在调用其上的用callback指示的函数,这些函数接受一个数组作为参数
  数组包含request,transport,json三项*/
  dispatch: function(callback, request, transport, json) {
    this.each(function(responder) {
      if (typeof responder[callback] == 'function') {
        try {
          responder[callback].apply(responder, [request, transport, json]);
        } catch (e) {}
      }
    });
  }
};

Object.extend(Ajax.Responders, Enumerable);

/*定义两个静态方法
onCreate和onComplete
*/
Ajax.Responders.register({
  onCreate: function() {
  /*做的工作很简单,增加一个活动链接数*/
    Ajax.activeRequestCount++;
  },
  onComplete: function() {
    Ajax.activeRequestCount--;
  }
});

Ajax.Base = function() {};
Ajax.Base.prototype = {
/*Ajax.Base的每个实例都有一个setOptions方法,此方法接收一个哈希对象作为参数,或者不传入参数,使用默认值*/
/*哈希对象的格式为{param1:value1,param2:value2...}*/
/*parameters为一个字符串,形为param1=value1&param2=value2....&paramn=valuen#dock*/
/*经过处理后parameters会被拆分然后填充到一个对象中去,对象的格式为
{param1=value1;param2=value2....paramn=valuen}
*/
/*默认值为
      method:       'post',
      asynchronous: true,
      contentType:  'application/x-www-form-urlencoded',
      encoding:     'UTF-8',
      parameters:   ''
  可能含有的其他参数
      postBody
      requestHeaders
      evalScripts(Ajax.Updater)
      insertion(Ajax.Updater)
      frequency(Ajax.PeriodicalUpdater)
      decay(Ajax.PeriodicalUpdater)
  可能含有的方法,用户只需要定义自己关心事件的回调函数。
      onSuccess
      onFailure
      on2xx
      on3xx
      on4xx
      on5xx
      onUninitialized
      onLoading
      onLoaded
      onInteractive
      onComplete
*/
/*usage
ajaxBaseInstance.setOptions( {postBody:"...",onSuccess:function(){...},onComplete:function(){...}} );
*/
  setOptions: function(options) {
    this.options = {
      method:       'post',
      asynchronous: true,
      contentType:  'application/x-www-form-urlencoded',
      encoding:     'UTF-8',
      parameters:   ''
    }
    Object.extend(this.options, options || {});

    this.options.method = this.options.method.toLowerCase();
    if (typeof this.options.parameters == 'string')
      this.options.parameters = this.options.parameters.toQueryParams();
  }
}

Ajax.Request = Class.create();
Ajax.Request.Events =
  ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];

Ajax.Request.prototype = Object.extend(new Ajax.Base(), {
  _complete: false,

  initialize: function(url, options) {
    this.transport = Ajax.getTransport();
    this.setOptions(options);
    /*新建一个AjaxRequest对象的时候直接发起请求*/
    this.request(url);
  },
               
  /*                      (如果state等于Complete)   (如果response是js代码)           
  /*onCreate---->onLoading------> on2xx -------------->调用evalResponse-----------> onUninitialized------
                                  on3xx                                             onLoading           |
                                  on4xx                                             onLoaded            |
                                  on5xx                                             onInteractive       | (transport状态更改会导致循环这个过程)
                                  onSuccess                                         onComplete          |
                                  onFailure                                                             |
                                    |___________________________________________________________________|
   注:所有这些函数均接受两个参数transport, json
  */
  request: function(url) {
    this.url = url;
    this.method = this.options.method;
    var params = Object.clone(this.options.parameters);

    /*如果this.method既不是get也不是post(在setOptions的时候被重写了,可能是put或者delete之类的)
    则把this.method的值保存在params._method中,并把this.method设置为post(因为不论put还是delete,
    其实都要向服务器端提交数据,在现有绝大部分浏览器仅支持get和post的情况下可以用post来模拟)*/
    if (!['get', 'post'].include(this.method)) {
      // simulate other verbs over post
      params['_method'] = this.method;
      this.method = 'post';
    }

    /*将params对象保存到this.parameters对象中,params将会保存toQueryString后的结果*/
    this.parameters = params;

    if (params = Hash.toQueryString(params)) {
      // when GET, append parameters to URL
      /*这里多说一句,万一我传入的url包含锚点符号怎么办?。。。*/
      if (this.method == 'get')
        this.url += (this.url.include('?') ? '&' : '?') + params;
      else if (/Konqueror|Safari|KHTML/.test(navigator.userAgent))
        params += '&_=';
    }

    try {
      if (this.options.onCreate) this.options.onCreate(this.transport);
      /*在创建Ajax调用之前*/
      /*对所有注册的Responders调用它们的onCreate方法*/
      Ajax.Responders.dispatch('onCreate', this, this.transport);

      /*发起一个Ajax调用,默认使用异步方法*/
      /*如果是同步的话会一直在这里等到连接建立或者超时*/
      this.transport.open(this.method.toUpperCase(), this.url,
        this.options.asynchronous);

      /*如果是使用异步调用,等待10毫秒后将会调用respondToReadyState方法,参数为1表示Loading状态*/
      /*人为的触发一个1xx事件(这个时候还没有使用onStateChange回调),以便于做一些等待时的处理,譬如显示一个Loading提示,或者进度条什么的*/
      if (this.options.asynchronous)
        setTimeout(function() { this.respondToReadyState(1) }.bind(this), 10);

      /*设置transport.onreadystatechange事件的回调函数为Ajax.Request.prototype.onStateChange*/
      /*无论是同步还是异步,这个onStatechange事件都会被调用*/
      this.transport.onreadystatechange = this.onStateChange.bind(this);
      this.setRequestHeaders();

      this.body = this.method == 'post' ? (this.options.postBody || params) : null;
      /*发送请求*/
      this.transport.send(this.body);

      /* Force Firefox to handle ready state 4 for synchronous requests */
      if (!this.options.asynchronous && this.transport.overrideMimeType)
        this.onStateChange();

    }
    catch (e) {
      this.dispatchException(e);
    }
  },
  
  /*
    1xx:信息响应类,表示接收到请求并且继续处理
    2xx:处理成功响应类,表示动作被成功接收、理解和接受
    3xx:重定向响应类,为了完成指定的动作,必须接受进一步处理
    4xx:客户端错误,客户请求包含语法错误或者是不能正确执行
    5xx:服务端错误,服务器不能正确执行一个正确的请求 
  */

  onStateChange: function() {
    var readyState = this.transport.readyState;
    if (readyState > 1 && !((readyState == 4) && this._complete/*在一个成功的调用之前,这个值一直都被设置为false*/))
      this.respondToReadyState(this.transport.readyState);
  },

  /*核心是调用transport.setRequestHeader方法*/
  setRequestHeaders: function() {
    var headers = {
      'X-Requested-With': 'XMLHttpRequest',
      'X-Prototype-Version': Prototype.Version,
      'Accept': 'text/javascript, text/html, application/xml, text/xml, */*'
    };

    if (this.method == 'post') {
      headers['Content-type'] = this.options.contentType +
        (this.options.encoding ? '; charset=' + this.options.encoding : '');

      /* Force "Connection: close" for older Mozilla browsers to work
       * around a bug where XMLHttpRequest sends an incorrect
       * Content-length header. See Mozilla Bugzilla #246651.
       */
      if (this.transport.overrideMimeType &&
          (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005)
            headers['Connection'] = 'close';
    }

    // user-defined headers
    if (typeof this.options.requestHeaders == 'object') {
      var extras = this.options.requestHeaders;

      if (typeof extras.push == 'function')
        for (var i = 0, length = extras.length; i < length; i += 2)
          headers[extras[i]] = extras[i+1];
      else
        $H(extras).each(function(pair) { headers[pair.key] = pair.value });
    }

    for (var name in headers)
      this.transport.setRequestHeader(name, headers[name]);
  },

  /*transport.status为false,null,undefined,NaN也表示success?*/
  /*或者transport.status为2xx*/
  success: function() {
    return !this.transport.status
        || (this.transport.status >= 200 && this.transport.status < 300);
  },

  respondToReadyState: function(readyState) {
    var state = Ajax.Request.Events[readyState];
    var transport = this.transport, json = this.evalJSON();

    /*查看this.options里面是否定义了onXXX(2xx~5xx)或者onSuccess或者onFailure方法*/
    /*如果定义了就调用相应的方法,如果没有定义则调用空方法*/
    if (state == 'Complete') {
      try {
      /*设置this._complete参数为true*/
        this._complete = true;
        (this.options['on' + this.transport.status]
         || this.options['on' + (this.success() ? 'Success' : 'Failure')]
         || Prototype.emptyFunction)(transport, json);
      } catch (e) {
        this.dispatchException(e);
      }

      /*通过比较响应的Content-type来查看是否是javascript代码,如果是,就动态eval返回的js代码*/
      var contentType = this.getHeader('Content-type');
      if (contentType && contentType.strip().
        match(/^(text|application)\/(x-)?(java|ecma)script(;.*)?$/i))
          this.evalResponse();
    }

    /*根据返回结果不同执行不同的回调函数*/
    /*
    onUninitialized
    onLoading
    onLoaded
    onInteractive
    onComplete
    */
    /*从代码可以看出来如果transport的状态码为4,这里会先后执行两个回调函数,
    首先是onXXX(2xx~5xx)或者onSuccess或者onFailure方法
    接着是上述函数之一*/
    try {
      (this.options['on' + state] || Prototype.emptyFunction)(transport, json);
      Ajax.Responders.dispatch('on' + state, this, transport, json);
    } catch (e) {
      this.dispatchException(e);
    }

    if (state == 'Complete') {
      // avoid memory leak in MSIE: clean up
      this.transport.onreadystatechange = Prototype.emptyFunction;
    }
  },

  getHeader: function(name) {
    try {
      return this.transport.getResponseHeader(name);
    } catch (e) { return null }
  },

  evalJSON: function() {
    try {
      var json = this.getHeader('X-JSON');
      return json ? json.evalJSON() : null;
    } catch (e) { return null }
  },

  evalResponse: function() {
    try {
      return eval((this.transport.responseText || '').unfilterJSON());
    } catch (e) {
      this.dispatchException(e);
    }
  },

  dispatchException: function(exception) {
  /*首先进行统一的异常处理(通过定义this.options.onException方法
  然后分别执行每个注册了的Responder的onException方法*/
    (this.options.onException || Prototype.emptyFunction)(this, exception);
    Ajax.Responders.dispatch('onException', this, exception);
  }
});

Ajax.Updater = Class.create();

/*这里有一个小技巧是先mixin,然后复写其中需要的方法*/
Object.extend(Object.extend(Ajax.Updater.prototype, Ajax.Request.prototype), {
  initialize: function(container, url, options) {
    /*这里用来指定Ajax调用成功和失败后分别用来更新的DOM对象
    参数可以是一个代表指定DOM元素的字符串(无论成功失败均更新此DOM对象),也可以是一个包含success和failure属性的对象*/
    this.container = {
      success: (container.success || container),
      failure: (container.failure || (container.success ? null : container))
    }

    this.transport = Ajax.getTransport();
    this.setOptions(options);

    /*在用户定义的onComplete事件前插入一个updateContent()事件*/
    /*这个updateContent事件是已经定义好的,所以无论用户是否定义onComplete,
    这个updateContent动作都是一定会执行的*/
    var onComplete = this.options.onComplete || Prototype.emptyFunction;
    this.options.onComplete = (function(transport, param) {
      this.updateContent();
      onComplete(transport, param);
    }).bind(this);

    this.request(url);
  },

  updateContent: function() {
    var receiver = this.container[this.success() ? 'success' : 'failure'];
    var response = this.transport.responseText;

    /*如果用户没有在options中指定evalScripts属性,会自动过滤掉返回结果中的<script...></script>标签*/
    if (!this.options.evalScripts) response = response.stripScripts();

    if (receiver = $(receiver)) {
      if (this.options.insertion)
        new this.options.insertion(receiver, response);
      else
        receiver.update(response);
    }

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

/*周期性的更新某个DOM*/
Ajax.PeriodicalUpdater = Class.create();
Ajax.PeriodicalUpdater.prototype = Object.extend(new Ajax.Base(), {
  initialize: function(container, url, options) {
    this.setOptions(options);
    this.onComplete = this.options.onComplete;

    this.frequency = (this.options.frequency || 2);
    this.decay = (this.options.decay || 1);

    this.updater = {};
    this.container = container;
    this.url = url;

    this.start();
  },

  start: function() {
    /*当transport状态变为complete的时候调用updateComplete方法*/
    this.options.onComplete = this.updateComplete.bind(this);
    this.onTimerEvent();
  },

  stop: function() {
    this.updater.options.onComplete = undefined;
    clearTimeout(this.timer);
    (this.onComplete || Prototype.emptyFunction).apply(this, arguments);
  },

  /*这个方法主要有两个作用:
  1.保存返回结果,主要是用来比较两次更新的结果,如果结果一直没有发生变化的话,更新的周期会呈指数性越来越长
  2.设置一个定时器,在decay*frequency秒后进行下下一次更新
  */
  updateComplete: function(request) {
    if (this.options.decay) {
      this.decay = (request.responseText == this.lastText ?
        this.decay * this.options.decay : 1);

      this.lastText = request.responseText;
    }
    this.timer = setTimeout(this.onTimerEvent.bind(this),
      this.decay * this.frequency * 1000);
  },

  onTimerEvent: function() {
    this.updater = new Ajax.Updater(this.container, this.url, this.options);
  }
});
 
分享到:
评论

相关推荐

    Really easy field validation with Prototype 1.5.4.1 中文修改版

    所做的更改: &lt;br&gt;1、prototype.js 版本更新为 v1.5.1.1 &lt;br&gt;2、effects.js 版本更新为 v1.7.1_beta3 &lt;br&gt;3、所有校验错误提示信息均修改为中文,提供UTF-8和GB18030两种编码的版本 &lt;br&gt;4、增加"YYYY-MM...

    prototype.js

    其中里面包含了prototype1.5 prototype1.5.1 prototype1.5.1.1 prototype1.5.1.2 prototype1.6.0。五个版本。 http://blog.csdn.net/boat1980/archive/2008/04/10/2278259.aspx这个连接有1.5.1.1代码的注释。

    Prototype.js

    Prototype.js (ver:1.5.1.1) Prototype.js 帮助(ver:1.5.1)英文PDF Prototype.js 帮助(ver:1.4)中文CHM Prototype.js 帮助(ver:1.4)中文PDF

    Prototype 1.5 中文手册.rar

    - `Prototype.extend`:此方法允许向对象添加新的属性或方法,实现对象的扩展。 - `Event`模块:提供事件处理相关的函数,如`observe`、`stopObserving`等,便于事件监听和移除。 3. Ajax功能: Prototype库的...

    Prototype 1.5 中文文档 chm

    Prototype 最新的1.5 版中文文档,chm格式,很多人都在找。Prototype 是一个非常优秀的javascript基础类库,可以很好的支持Ajax,国外有多个基于此类库的扩展,这是最新的1.5中文文档,AJAX编程必备手册。

    prototype中文手册及API

    prototype中文手册及API --------------------- prototype.js(1.5.1.1) prototype中文手册 prototype.chm

    prototype-1.6.0.3.js+prototype1.4 、1.5中文手册+prototype1.6英文手册

    这个压缩包包含了Prototype库的多个版本的手册和源代码文件,便于开发者理解和使用。 首先,我们来看`prototype-1.6.0.3.js`,这是Prototype库的1.6.0.3版本的源代码文件。在这个版本中,Prototype提供了许多实用的...

    prototype_1.7.3.js 最新版本

    《prototype_1.7.3.js:JavaScript框架的里程碑》 在JavaScript的世界里,Prototype库是一个不可...无论你是新手还是经验丰富的开发者,掌握Prototype.js都能让你在Web开发中如虎添翼,进一步提升代码质量和开发效率。

    prototype.js 源码解读, 中文帮助文档

    开发者网站: http://prototype.conio.net/ prototype学习资料包括: prototype14参考 prototype 1.3 源码解读.txt prototype 1.5 参考图 prototype 1.5pre1.js prototype 1.4.js

    prototype1.6.0.2.js

    prototype1.6.0.2

    prototype 1.6.0.2.js+使用DEMO例子

    通过提供的DEMO例子,开发者可以直观地看到Prototype在实际项目中的应用,理解如何将这些工具和方法融入到自己的代码中。实践中,可能包括创建动态页面、实现异步数据交互、优化DOM操作等方面。 总的来说,这个...

    prototype1.5中文说明

    通过阅读`Prototype.doc`文档,你可以深入了解Prototype库的每个细节,学习如何有效地利用这些功能来构建高效、动态的Web应用程序。无论你是JavaScript新手还是经验丰富的开发者,Prototype 1.5RC2都是一个值得学习...

    基于ASP的风铃ASP文件共享系统(多文件上传) v1.5.zip

    ASP允许开发者使用各种组件来扩展功能,例如使用FileSystemObject来处理文件操作,使用ADODB.Stream处理二进制数据,或者使用XMLHTTP对象实现Ajax无刷新上传。此外,可能还会有第三方库如JQuery或Prototype来增强...

    prototype 1.6中文手册 chm+prototype 1.6.js源码 最新版

    包含的"prototype.js"文件是Prototype 1.6.0的源代码,这对于开发者来说是一份宝贵的参考资料。通过阅读源码,开发者可以直接了解每个函数的实现细节,理解其工作原理,从而更好地应用到自己的项目中。源码中的注释...

    prototype1.5

    《Prototype 1.5:JavaScript 引领Ajax技术新里程》 Prototype 1.5,作为JavaScript库的一个重要里程碑,为Web开发引入了强大的功能和灵活性,尤其在处理Ajax(异步JavaScript和XML)交互方面。这个版本的发布极大...

    prototype.js 1.6中文手册、prototype.js 1.6英文手册、

    **Prototype.js 1.6 知识点详解** Prototype.js 是一个开源的JavaScript库,它扩展了JavaScript语言,为开发者提供了许多便利的功能,特别是在对象操作、DOM操作和事件处理方面。1.6版本是该库的一个重要里程碑,...

    prototype1.6.1 .js

    prototype1.6.1 .js 时下流行的前端开发javascript类库

    使用Prototype框架.pdfprototype源码分析.doc

    例解Prototype框架.doc 第21章__使用Prototype框架.pdf Prototype源码注释版.pdf proprototype源码分析.doc totype_1.3_源码解读.txt

    Prototype.and.script.aculo.us.Dec.2007.pdf

    #### 1.1 Prototype框架 Prototype是最早的JavaScript库之一,它简化了DOM操作,提供了一套强大的功能,如AJAX支持、事件处理、DOM遍历和修改等。它通过扩展原生JavaScript对象(如Array和String),使得开发人员...

    prototype1.6.0.3.rar

    《Prototype JavaScript 框架详解:以 prototype1.6.0.3.rar 文件为中心》 在Web开发领域,JavaScript框架的出现极大地提升了开发效率和代码质量。Prototype JavaScript框架,作为一个历史悠久且广泛使用的库,为...

Global site tag (gtag.js) - Google Analytics