WebRequestExecutor和XMLHttpExecutor
XMLHttpExecutor
大部分的属性与方法的意义实在不大。我们就来看几个关键方法的实现吧,它们会涉及到WebRequestExecutor的状态,即使我们的实现不同,这些状态一般来说还是保持统一的。
1、构造函数
构造函数的作用其实只是初始化所有的状态,它们分别是:
* responseAvailable属性设为false
* timedOut属性设为false
* aborted属性设为false
* started属性设为false
2、executeRequest方法
调用这个方法就会构造一个XMLHttpRequest对象,并发起一个请求。代码如下:
function Sys$Net$XMLHttpExecutor$executeRequest() {
if (arguments.length!== 0)throw Error.parameterCount();
// 通过get_webRequest方法获得当前的WebRequest,
// 这个是Sys.Net.WebRequestExecutor的方法。
this._webRequest= this.get_webRequest();
// 如果已经开始过了,那么抛出异常
if (this._started) {
throw Error.invalidOperation(String.format(Sys.Res.cannotCallOnceStarted, 'executeRequest'));
}
// 如果没有指定WebRequest,也会抛出异常。
if (this._webRequest=== null) {
throw Error.invalidOperation(Sys.Res.nullWebRequest);
}
// 构造XMLHttpRequest对象并设定各项值
var body= this._webRequest.get_body();
var headers= this._webRequest.get_headers();
this._xmlHttpRequest= new XMLHttpRequest();
this._xmlHttpRequest.onreadystatechange= this._onReadyStateChange;
var verb= this._webRequest.get_httpVerb();
this._xmlHttpRequest.open(verb,this._webRequest.getResolvedUrl(),true );
// 添加header
if (headers) {
for (var headerin headers) {
var val= headers[header];
if (typeof(val)!== "function")
this._xmlHttpRequest.setRequestHeader(header, val);
}
}
// 如果使用POST方法
if (verb.toLowerCase()=== "post") {
// 则需要设置Content-Type
if ((headers=== null)|| !headers['Content-Type']) {
this._xmlHttpRequest.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
}
if (!body) {
body= "";
}
}
// 如果指定了timeout时间
var timeout= this._webRequest.get_timeout();
if (timeout> 0) {
// 则取消
this._timer= window.setTimeout(Function.createDelegate(this,this._onTimeout), timeout);
}
this._xmlHttpRequest.send(body);
// 表明已经开始了
this._started= true;
} 可以发现,在这个方法被调用之后,started属性被设为了true,以此避免同一个Executor被执行两次。
3、_onReadyStateChange方法
这个方法是XMLHttpRequest对象的onreadystatechange回调函数。代码如下:
this._onReadyStateChange= function () {
// 当xmlHttpRequest执行完毕后
if (_this._xmlHttpRequest.readyState=== 4 ) {
// 清除timeout定时器
_this._clearTimer();
// 将responseAvailable属性设为true
_this._responseAvailable= true;
// 触发WebRequestManager的completedRequest事件和WebRequest的completed事件
_this._webRequest.completed(Sys.EventArgs.Empty);
// 释放XMLHttpRequest对象
if (_this._xmlHttpRequest!= null) {
_this._xmlHttpRequest.onreadystatechange= Function.emptyMethod;
_this._xmlHttpRequest= null;
}
}
} 在这个方法里,只会判断 XMLHttpRequest对象的readyState的值,等于4则表示收到了回复,已经执行完毕了,然后进入其他逻辑。这个和“标准 ”的AJAX逻辑似乎有些不同,这是因为在ASP.NET AJAX中的WebRequestExecutor中,会将判断response结果的逻辑交由其它代码完成。在Executor中只需表示 “Complete”即可,其余的,都交给别人去吧。
在这个方法中,responseAvailable被设为了true,表示已经得到了Response——其实在ASP.NET AJAX这部分模型中,这个Response对象就是当前的WebRequestExectuor自身。
4、_onTimeout方法
timeout触发器会调用这个方法。代码如下:
this._onTimeout= function this$_onTimeout() {
// 可能在timeout触发时已经获得结果了,
// 排出这种状况
if (!_this._responseAvailable) {
// 清除timeout触发器
_this._clearTimer();
// timeout设为true
_this._timedOut= true;
// 取消XMLHttpRequest所用的回调函数
_this._xmlHttpRequest.onreadystatechange= Function.emptyMethod;
// 取消XMLHttpRequest对象的操作
_this._xmlHttpRequest.abort();
// 触发WebRequest的completed事件
_this._webRequest.completed(Sys.EventArgs.Empty);
// 释放XMLHttpRequest对象
_this._xmlHttpRequest= null;
}
} 当一个请求超时的时候,需要调用XMLHttpRequest.abort方法来取消这个请求。同时,timeout属性被设为了true。
5、abort方法
这个方法负责取消一个请求。代码如下:
function Sys$Net$XMLHttpExecutor$abort() {
if (arguments.length!== 0)throw Error.parameterCount();
// 如果还没有开始,则抛出异常
if (!this._started) {
throw Error.invalidOperation(Sys.Res.cannotAbortBeforeStart);
}
// 如果已经被取消了或者已经超时了,则返回
if (this._aborted|| this._responseAvailable|| this._timedOut)
return;
// 将abort属性设为true
this._aborted= true;
// 清除超时触发器
this._clearTimer();
// 保险起见,需要判断是否已经执行完毕了
if (this._xmlHttpRequest&& !this._responseAvailable) {
this._xmlHttpRequest.onreadystatechange= Function.emptyMethod;
this._xmlHttpRequest.abort();
this._xmlHttpRequest= null;
var handler= this._webRequest._get_eventHandlerList().getHandler("completed");
if (handler) {
handler(this, Sys.EventArgs.Empty);
}
}
} 这个方法会调用XMLHttpRequest对象的abort方法来取消这个请求,并且将aborted属性设为true。
上面就是XMLHttpExecutor类的“分析”了,其实代码都非常简单(有时候我会想,难道我是为了系列文章内容的完整性才写这些吗?它们的质量有没有到一定的标准?它们有一定的存在价值吗?)。我们来思考一个问题,到底什么时候我们需要自定义一个Executor?我们需要满足一个什么样的功能?在实际应用中XMLHttpRequest的功能还不够吗?写一个IFrameExecutor?个人认为,一般来说,如果真的要对 WebRequestExecutor进行扩展的话,估计也是在XMLHttpExecutor的基础上进行扩展了,我们可以依靠对于 XMLHttpExecutor的继承或者封装附加一些新的功能,例如统一的身份验证和异常处理等等。在与这篇“分析”相对应的 “示例”中,我将提供一个继承于XMLHttpExecutor的类,它能够将页面上所有请求的全部或部分信息输出在页面上,方便开发人员跟踪与调试。当然,这只是一个在开发过程中的应用。至于完整定义一个WebRequestExecutor...那么为客户端的单元测试定义一个WebRequestExecutor的mock对象吧。
匿名2008-08-17 10:25:5659.41.99.*