Error.popStackFrame 函数
2013-01-28 22:39 Hejin.Wong 阅读(1108) 评论(1) 编辑 收藏 举报为了让客户端编程 和.NET样式的编程尽可一样。ASP.NET AJAX客户端框架对 JavaScript基本类型进行了扩展。
Error类型扩展——create函数
create 函数是一个静态函数。它允许用户创建一个具有额外错误信息的新Error对象。此函数有两个参数,第一个参数是错误信息,第二个参数是一个可选对象,该对 象具有相关属性来提供更多关于错误的信息。对象必须有一个name属性,它唯一地确定错误类型。其余的属性可以拥有任意的名称和属性,但最好有对应的直观 意义.
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" /> 45 <input type="button" value="Validate" onclick="clickCallback()" /> 46 </form> 47 </body> 48 </html>
当输入的日期内容不符合正则表达式或为空时,validateInput函数将抛出异常。
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不一样。
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" /> 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)的信息。每个堆栈帧对应一个特定的函数调用。
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" /> 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
参考:
《ASP.NET AJAX 编程参考手册》