性能考虑
当错误对象被抛出时,开始堆栈跟踪的构造;这样做需要追踪到当前执行的堆栈。为了防止在遍历一个大堆栈(或许是一个递归堆栈)时的性能问题,默认的情况下IE只收集前十的堆栈帧,当然这个设置可以配置,你可以设置静态属性Error.stackTraceLimitto为其他的值。这个配置是全局的,并且必须在错误抛出之前设置,否则它不会产生跟踪堆栈的效果。
异步的异常
当一个堆栈跟踪产生于一个异步的回调时(比如,timeout,interval, 或者XMLHttpRequest),异步调用,而不是在调用堆栈的底部创建异步调用的代码。这里存在一些跟踪问题代码的潜在影响:如果你对于多个异步回调使用相同的回调函数,你或许会发现很难查找出某一个单独的回调引起的错误。让我们稍微修改下之前的例子,替换直接调用simple(),采用timeout函数回调方法调用:
'use strict';
function squareRoot(n) {
if (n < 0)
throw new Error('Cannot take square root of negative number.');
return Math.sqrt(n);
}
function square(n) {
return n * n;
}
function pointDistance(pt1, pt2) {
return squareRoot((pt1.x - pt2.x) + (pt1.y - pt2.y));
}
function sample() {
var pt1 = { x: 0, y: 2 };
var pt2 = { x: 12, y: 10 };
console.log('Distance is: ' + pointDistance(pt1, pt2));
}
setTimeout(function () {
try {
sample();
}
catch (e) {
console.log(e.stack);
}
}, 2500);
})();
在执行这段代码时,你会看到堆栈跟踪稍微有些延迟,这次你也会看到堆栈的底层不是全局的代码而是一个匿名函数。实际上,它们不是使用同一个匿名函数,而是回调函数传递给setTimeout,由于你失去了回调的上下文环境,你也就无法确认哪个回调被调用了。如果你考虑这样的一个场景,一个回调被注册到多个不同按钮的点击事件上,你将无法确认引用的是哪个注册的回调。那就是说,这个限制只是次要的,因为在大多数情况下,堆栈顶部会突出问题区域。
探索测试驱动例子
在windows8系统下使用IE10检查这个测试例子Test Drive demo。你可以使用eval执行代码,如果发生了错误,你能及时检查到它。如果你在IE10下运行它,当你把鼠标放在错误堆栈上时,错误代码行会突出显示。你可以在代码区自己输入代码,或者在列表中例子里选择一个。你也可以在运行示例代码时设置Error.stackTraceLimitvalue。
作为参考资料,你可以浏览MSDN关于Error.stack和stackTraceLimit的文档。
这篇文章作者是Rob Paveza. Rob是IE团队的一个项目经理,主要研究Chakra,一个新型的javascript运行引擎。