代码改变世界

Error.popStackFrame 函数

2013-01-28 22:39  Hejin.Wong  阅读(1108)  评论(1编辑  收藏  举报

为了让客户端编程 和.NET样式的编程尽可一样。ASP.NET AJAX客户端框架对 JavaScript基本类型进行了扩展。

Error类型扩展——create函数

create 函数是一个静态函数。它允许用户创建一个具有额外错误信息的新Error对象。此函数有两个参数,第一个参数是错误信息,第二个参数是一个可选对象,该对 象具有相关属性来提供更多关于错误的信息。对象必须有一个name属性,它唯一地确定错误类型。其余的属性可以拥有任意的名称和属性,但最好有对应的直观 意义.

View Code
 1 <%@ Page Language="C#" %>
 2 
 3 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 4 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 5 <html xmlns="http://www.w3.org/1999/xhtml">
 6 <head runat="server">
 7   <title>Untitled Page</title>
 8 
 9   <script language="javascript" type="text/javascript">
10     function validateInput(input)
11     {
12       var reg = new RegExp("(\\d\\d)[-/](\\d\\d)[-/](\\d\\d(?:\\d\\d)?)");
13       var date = reg.exec(input);
14       if (date == null)
15       {
16         var err = Error.create("Please enter a valid date!",
17         {name : "MyError", errorNumber : 234});
18         throw err;
19       }
20     }
21     
22     function clickCallback()
23     {
24       var date = document.getElementById("date");
25       try
26       {
27         validateInput(date.value);
28       }
29       catch (e)
30       {
31         alert("Error Message: " + e.message + "\nError Number: " + e.errorNumber
32         + "\nDocument: " + e.fileName
33         + "\nLine Number: " + e.lineNumber);
34         date.value = "";
35       }
36     }
37   </script>
38 
39 </head>
40 <body>
41   <form id="form1" runat="server">
42   <asp:ScriptManager runat="server" ID="ScriptManager1" />
43   Enter date:
44   <input type="text" id="date" />&nbsp;
45   <input type="button" value="Validate" onclick="clickCallback()" />
46   </form>
47 </body>
48 </html>

 

当输入的日期内容不符合正则表达式或为空时,validateInput函数将抛出异常。

 

Error.create内部实现
 1 Error.create =function(d, b)
 2 {
 3     var a = new    Error(d);
 4     a.message =    d;
 5     if (b)    
 6     for(var c in b)
 7     a [c] = b[c];
 8     a.popStackFrame();
 9     return a
10 };

页面中定义的{name : "MyError", errorNumber : 234}对象,通过下面语句赋值给Error对象:

1 for(var c in b)
2     a [c] = b[c];

popStackFrame 函数

fileName和lineNumber属性设置为Error对象创建处的文档URL和行号。lineNumber跟errorNumber不一样。

自定义Create方法
 1 <%@ Page Language="C#" %>
 2 
 3 <!DOCTYPE html PUBLIC
 4 "-//W3C//DTD XHTML 1.0 Transitional//EN"
 5 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 6 <html xmlns="http://www.w3.org/1999/xhtml">
 7 <head id="Head1" runat="server">
 8   <title>Untitled Page</title>
 9 
10   <script language="javascript" type="text/javascript">
11     function MyErrorCreate(d, b)
12     {
13       var a = new Error(d);
14       a.message = d;
15       if(b)
16         for(var c in b)
17           a[c] = b[c];
18       //a.popStackFrame();
19       return a
20     };
21     
22     function validateInput(input)
23     {
24       var reg = new RegExp("(\\d\\d)[-/](\\d\\d)[-/](\\d\\d(?:\\d\\d)?)");
25       var date = reg.exec(input);
26       if (date == null)
27       {
28         var err = MyErrorCreate("Please enter a valid date!",
29         {name : "MyError", errorNumber : 234});
30         throw err;
31       }
32     }
33     
34     function clickCallback()
35     {
36       var date = document.getElementById("date");
37       try
38       {
39         validateInput(date.value);
40       }
41       catch (e)
42       {
43         alert("Error Message: " + e.message + "\nError Number: " + e.errorNumber +
44         "\nDocument: " + e.fileName + "\nLine Number: " + e.lineNumber);
45         date.value = "";
46       }
47     }
48   </script>
49 
50 </head>
51 <body>
52   <form id="form1" runat="server">
53   <asp:ScriptManager runat="server" ID="ScriptManager1" />
54   Enter date:
55   <input type="text" id="date" />&nbsp;
56   <input type="button" value="Validate" onclick="clickCallback()" />
57   </form>
58 </body>
59 </html>

当MyErrorCreate方法中将语句"a.popStackFrame();"注释掉,访问页面,输入无效的日期,你将看到

此时页面代码 如下图:

lineNumber为Error对象创建处行号。errorNumber的行号则是有{name : "MyError", errorNumber : 234}对象属性决定的。

如果我们将去掉语句"a.popStackFrame();"的注释,访问页面输入无效的日期点击按钮,你将看到

这次的lineNumber行号改变了-30, 就是validateInput函数抛出异常的地方。

     

当您在创建 Error 实例的函数内调用该实例的 popStackFrame 方法时,将更新该错误实例的 fileName 和 lineNumber 字段。 这些字段的值根据引发错误的位置而不是创建 Error 实例的位置设置。 popStackFrame 函数根据浏览器堆栈跟踪中的下一帧更新 Error 实例的 fileName 和 lineNumber 字段。

popStackFrame 的内部机理

Error对象的一个重要属性,即stack。它是一个包含一系列子字符串列表的字符串,其中的子字符串用”\n"分开,每个子字符串中都包含了某个特定堆栈帧(stack frame)的信息。每个堆栈帧对应一个特定的函数调用。

View Code
 1 <%@ Page Language="C#" %>
 2 
 3 <!DOCTYPE html PUBLIC
 4 "-//W3C//DTD XHTML 1.0 Transitional//EN"
 5 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 6 <html xmlns="http://www.w3.org/1999/xhtml">
 7 <head id="Head1" runat="server">
 8   <title>Untitled Page</title>
 9 
10   <script language="javascript" type="text/javascript">
11     function getStack(err)
12     {
13         var a = err.stack.split("\n");
14         Array.forEach(a, function(item, i,array)
15         {
16         array[i] = String.format("a[{0}]={1}",i,item);
17         });
18         alert(a.join("\n"));
19     }
20     
21     function validateInput(input)
22     {
23       var reg = new RegExp("(\\d\\d)[-/](\\d\\d)[-/](\\d\\d(?:\\d\\d)?)");
24       var date = reg.exec(input);
25       if (date == null)
26       {
27         var err = Error.create("Please enter a valid date!",
28         {name : "MyError", errorNumber : 234});
29         getStack(err);
30         err.popStackFrame();
31         throw err;
32       }
33     }
34     
35     function clickCallback()
36     {
37       var date = document.getElementById("date");
38       try
39       {
40         validateInput(date.value);
41       }
42       catch (e)
43       {
44         getStack(e);
45         date.value = "";
46       }
47     }
48   </script>
49 
50 </head>
51 <body>
52   <form id="form1" runat="server">
53   <asp:ScriptManager runat="server" ID="ScriptManager1" />
54   Enter date:
55   <input type="text" id="date" />&nbsp;
56   <input type="button" value="Validate" onclick="clickCallback()" />
57   </form>
58 </body>
59 </html>

访问页面,通过firebug在脚本中语句上"getStack(err);"设置断点,输入无效的日期点击按钮,页面在断点处中断,

在左边的监控处err.stack属性为:

  此错误堆栈包括三个主要的堆栈帧,其中每个帧代表一个特殊的函数调用。 例如,第一个堆栈帧表示调用函数validatelnput。每个堆栈帧包括两部分,它 们之间用@字符隔开,第一部分表示函数调用。第二部分本身又包括两部分,用冒号(:)隔开, 前一部分表示文档的URL,后一部分表示文档中的行号。

 

按"F10",开始执行下一句,此时弹出如下页面

继续按"F10",当语句执行到" line 32 : throw err;"处,此时的err.stack属性为

 当执行clickCallback 函数getStack(e);语句后,页面弹出

“validateInput@http://localhost:15401/create.aspx:29”没有了。

 1 Error.prototype.popStackFrame =function() 
 2 {
 3     
 4     if (typeof this.stack ==="undefined" || this.stack === null    || typeof this.fileName === "undefined" || this.fileName === null || typeof this.lineNumber ==== "undefined" || this.lineNumber === null )
 5     return ;    
 6     var a = this.stack.split("\n"),        
 7         c = a[0],        
 8         e = this.fileName + ":" + this.lineNumber;    
 9     while(typeof c !== "undefined" && c !== null && c.indexOf(e) === -1)
10     {
11         a.shift();        
12         c = a [0]
13     }        
14     var d = a[1];        
15     if(typeof d === "undefined" || d === null)    
16         return;        
17     var b = d.match(/@(.*):(\d+)$/);        
18     if (typeof b === "undefined" || b =====    null)    
19         return;        
20 
21     this.fileName = b[l];
22     this.lineNumber = parseInt(b[2]);
23     a.shift();
24     this.stack = a.join("\n")
25 
26 }

语句 e = this.fileName + ":" + this.lineNumber;  e的值为“http://localhost:15401/create.aspx:29”,上面我们提到lineNumber的值为Error对象创建的时的行号。就是下面的语句(上面的截图 line :29)——正确的应该是line 41处。

 

  var err = Error.create("Please enter a valid date!",
        {name : "MyError", errorNumber : 234});

 

c的值为"validateInput@http://localhost:15401/create.aspx:29",e的值为“http://localhost:15401/create.aspx:29”,由下面的while语句将“validateInput@http://localhost:15401/create.aspx:29”移出了最顶部的堆栈帧。  

1 while(typeof c !== "undefined" && c !== null && c.indexOf(e) === -1)
2 {
3     a.shift();        
4     c = a [0]
5 }

 

测试环境:VS2008  .NET Framework 3.5

浏览器:firefox 18.0

参考:

Error.popStackFrame 函数

《ASP.NET AJAX 编程参考手册》