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¶m2=value2....¶mn=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);
}
});
分享到:
相关推荐
所做的更改: <br>1、prototype.js 版本更新为 v1.5.1.1 <br>2、effects.js 版本更新为 v1.7.1_beta3 <br>3、所有校验错误提示信息均修改为中文,提供UTF-8和GB18030两种编码的版本 <br>4、增加"YYYY-MM...
其中里面包含了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 (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.extend`:此方法允许向对象添加新的属性或方法,实现对象的扩展。 - `Event`模块:提供事件处理相关的函数,如`observe`、`stopObserving`等,便于事件监听和移除。 3. Ajax功能: Prototype库的...
Prototype 最新的1.5 版中文文档,chm格式,很多人都在找。Prototype 是一个非常优秀的javascript基础类库,可以很好的支持Ajax,国外有多个基于此类库的扩展,这是最新的1.5中文文档,AJAX编程必备手册。
prototype中文手册及API --------------------- prototype.js(1.5.1.1) prototype中文手册 prototype.chm
这个压缩包包含了Prototype库的多个版本的手册和源代码文件,便于开发者理解和使用。 首先,我们来看`prototype-1.6.0.3.js`,这是Prototype库的1.6.0.3版本的源代码文件。在这个版本中,Prototype提供了许多实用的...
《prototype_1.7.3.js:JavaScript框架的里程碑》 在JavaScript的世界里,Prototype库是一个不可...无论你是新手还是经验丰富的开发者,掌握Prototype.js都能让你在Web开发中如虎添翼,进一步提升代码质量和开发效率。
开发者网站: 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
通过提供的DEMO例子,开发者可以直观地看到Prototype在实际项目中的应用,理解如何将这些工具和方法融入到自己的代码中。实践中,可能包括创建动态页面、实现异步数据交互、优化DOM操作等方面。 总的来说,这个...
通过阅读`Prototype.doc`文档,你可以深入了解Prototype库的每个细节,学习如何有效地利用这些功能来构建高效、动态的Web应用程序。无论你是JavaScript新手还是经验丰富的开发者,Prototype 1.5RC2都是一个值得学习...
ASP允许开发者使用各种组件来扩展功能,例如使用FileSystemObject来处理文件操作,使用ADODB.Stream处理二进制数据,或者使用XMLHTTP对象实现Ajax无刷新上传。此外,可能还会有第三方库如JQuery或Prototype来增强...
包含的"prototype.js"文件是Prototype 1.6.0的源代码,这对于开发者来说是一份宝贵的参考资料。通过阅读源码,开发者可以直接了解每个函数的实现细节,理解其工作原理,从而更好地应用到自己的项目中。源码中的注释...
《Prototype 1.5:JavaScript 引领Ajax技术新里程》 Prototype 1.5,作为JavaScript库的一个重要里程碑,为Web开发引入了强大的功能和灵活性,尤其在处理Ajax(异步JavaScript和XML)交互方面。这个版本的发布极大...
**Prototype.js 1.6 知识点详解** Prototype.js 是一个开源的JavaScript库,它扩展了JavaScript语言,为开发者提供了许多便利的功能,特别是在对象操作、DOM操作和事件处理方面。1.6版本是该库的一个重要里程碑,...
prototype1.6.1 .js 时下流行的前端开发javascript类库
例解Prototype框架.doc 第21章__使用Prototype框架.pdf Prototype源码注释版.pdf proprototype源码分析.doc totype_1.3_源码解读.txt
#### 1.1 Prototype框架 Prototype是最早的JavaScript库之一,它简化了DOM操作,提供了一套强大的功能,如AJAX支持、事件处理、DOM遍历和修改等。它通过扩展原生JavaScript对象(如Array和String),使得开发人员...
《Prototype JavaScript 框架详解:以 prototype1.6.0.3.rar 文件为中心》 在Web开发领域,JavaScript框架的出现极大地提升了开发效率和代码质量。Prototype JavaScript框架,作为一个历史悠久且广泛使用的库,为...