上一部分说道在发送前,已经将回调函数赋值成
xmlRequest.onreadystatechange = WebForm_CallbackComplete;
那么咱们就先来看看这个callback方法。
function WebForm_CallbackComplete() {
    
for (i = 0; i < __pendingCallbacks.length; i++{
        callbackObject 
= __pendingCallbacks[i];
        
if (callbackObject && callbackObject.xmlRequest && (callbackObject.xmlRequest.readyState == 4)) {
            WebForm_ExecuteCallback(callbackObject);
            
if (!__pendingCallbacks[i].async) {
                __synchronousCallBackIndex 
= -1;
            }

            __pendingCallbacks[i] 
= null;
            
var callbackFrameID = "__CALLBACKFRAME" + i;
            
var xmlRequestFrame = document.getElementById(callbackFrameID);
            
if (xmlRequestFrame) {
                xmlRequestFrame.parentNode.removeChild(xmlRequestFrame);
            }

        }

    }

}
这是获得一个挂起的未处理回调队列,并且如果队列里面的是以xmlrequest发送的ajax的请求,而且状态为4的话,那么调用方法:WebForm_ExecuteCallback方法。
当然如果是通过iframe来发送ajax请求的话,那么就是将先前的iframe移除掉。
下一部分就是WebForm_ExecuteCallback方法:
function WebForm_ExecuteCallback(callbackObject) {
    
var response = callbackObject.xmlRequest.responseText;
    
if (response.charAt(0== "s"{
        
if ((typeof(callbackObject.eventCallback) != "undefined"&& (callbackObject.eventCallback != null)) {
            callbackObject.eventCallback(response.substring(
1), callbackObject.context);
        }

    }

    
else if (response.charAt(0== "e"{
        
if ((typeof(callbackObject.errorCallback) != "undefined"&& (callbackObject.errorCallback != null)) {
            callbackObject.errorCallback(response.substring(
1), callbackObject.context);
        }

    }

    
else {
        
var separatorIndex = response.indexOf("|");
        
if (separatorIndex != -1{
            
var validationFieldLength = parseInt(response.substring(0, separatorIndex));
            
if (!isNaN(validationFieldLength)) {
                
var validationField = response.substring(separatorIndex + 1, separatorIndex + validationFieldLength + 1);
                
if (validationField != ""{
                    
var validationFieldElement = theForm["__EVENTVALIDATION"];
                    
if (!validationFieldElement) {
                        validationFieldElement 
= document.createElement("INPUT");
                        validationFieldElement.type 
= "hidden";
                        validationFieldElement.name 
= "__EVENTVALIDATION";
                        theForm.appendChild(validationFieldElement);
                    }

                    validationFieldElement.value 
= validationField;
                }

                
if ((typeof(callbackObject.eventCallback) != "undefined"&& (callbackObject.eventCallback != null)) {
                    callbackObject.eventCallback(response.substring(separatorIndex 
+ validationFieldLength + 1), callbackObject.context);
                }

            }

        }

    }

}

这部分就是返回的值如果是以e开头的话调用异常方法,证明服务器端出错,如果以's'开头或者存在'|'字符的话,那么就调用回调成功的方法,如果以'e'开头的话那么就调用错误处理方法,如果你注册了的话。

在实际的测试中,我改变几种策略来揣摩它的机制:
服务器端直接抛出异常:结果用抓包工具观察到果然是返回'e'。
public String GetCallbackResult() 方法直接response.write一个字符串,但是却不返回数据,并catch住当前模块,目的是想直接输出某些东西,并且绕过它自有的实现机制,比如自由控制异常与否,自由控制异常,但是结果抓包显示:e正在中止线程。也就是说response.write使得当前线程终止了,这个异常被它捕获到并且返回给了客户端。
另外一个变通:将服务器重定向。
public String GetCallbackResult()
    
{
     
        
try
        
{
            Response.Redirect(
"http://www.163.com");
         
//   Response.Write("asd");
            Response.End();

        }

        
catch { }
        
finally
        
{

        }
 return "";
    }
这样的话,跟踪到的结果确是 0| 也就是说看起来正常。前一种测试它能捕获到异常,说明客户端回调的回调结果处理应该在response.end之后,那么应该就是在endrequest这个阶段做的回调结果返回的处理。(没有记错的话beginrequest是模块里面最后一个了。)而redirect方法(304重定向)却不会触发这个事件,所以服务器端没有捕获到而只是返回了结果。


好了,整个已经研究完了,我想来说点感想,首先是这个做得是比较完美,如果不支持xmlrequest对象,还采用了iframe的形式来进行支持,不过多写了好多代码.......另外是否能将其优化为在服务器端智能判断客户端的浏览器类型,然后输出js文件呢?不支持xmlrequest对象的浏览器应该能从客户端发送过来的客户端环境变量中检索出来,并且让各客户端各取所需,那样不是很好吗?这样就不会造成在ie和ff浏览器99% 份额的时候为了1%而不必要做了如下的冗余措施:
在浏览器尚未加载完的时候调用WebForm_InitCallback将页面所有的控件和值作为键值对存储起来,并将其encode。这个操作显得非常多余。而且浪费时间和资源。
同时也看到了asp.net发送了很多与之无关的代码都发送了过来,比如只有在MaintainScrollPositionOnPostback为true的时候才需要的代码,以及页面上有Defaultbutton的时候才有的代码等等,都一股脑全部过来了。实在是有些浪费资源。另外看到asp.net的js脚本代码写的也不是很省,比如这段:
var callback = new Object();
    callback.eventCallback 
= eventCallback;
    callback.context 
= context;
    callback.errorCallback 
= errorCallback;
    callback.async 
= useAsync;

可以改成:
var callback = {eventCallback:eventCallback,context:context,errorCallback:errorCallback,async:useAsync}
这在prototype框架中经常见到,这样写避免了使用with语句来消耗资源,也减少了很多代码,节省了字节数。

所以asp.net在快速开发这一块的确是非常好,但是也封装了不少东西,在企业级的应用当中,要想获得更好的性能还是只有自己手写不少代码,来弥补性能,当然,asp.net也留下了不少可扩展的空间,只要你熟悉它的机制。
下一篇文章我帖一下我这次收获的其他东西。

错误有所难免,希望大侠们指教!
posted on 2007-07-26 08:15  silverlightfans  阅读(2249)  评论(2编辑  收藏  举报