Actionscript 3 AS3从事件回调报告错误
我一直在尝试在AS3的异步代码中发生错误时提供更好的调试信息 作为默认错误报告不佳的一个示例,以我在计时器回调中强制使用空指针为例,我在控制台上得到以下stacktrace:Actionscript 3 AS3从事件回调报告错误,actionscript-3,debugging,actionscript,asynchronous,event-handling,Actionscript 3,Debugging,Actionscript,Asynchronous,Event Handling,我一直在尝试在AS3的异步代码中发生错误时提供更好的调试信息 作为默认错误报告不佳的一个示例,以我在计时器回调中强制使用空指针为例,我在控制台上得到以下stacktrace: TypeError: Error #1009: Cannot access a property or method of a null object reference. at Function/<anonymous>()[/[path-to-source-file]/TestClass.as:14]
TypeError: Error #1009: Cannot access a property or method of a null object reference.
at Function/<anonymous>()[/[path-to-source-file]/TestClass.as:14]
at flash.utils::Timer/_timerDispatch()
at flash.utils::Timer/tick()
这很少告诉我计时器回调实际上是如何链接到我的代码的
问题是:我如何获得关于创建回调的代码的信息
我在下面添加了我的一个解决方案。我很想看看这是否可以改进。一个可能的解决方案是在使用者线程/作用域中预先创建一个错误对象
var errorInConsumerScope:Error = new Error()
var timer:Timer = new Timer(1000, 1)
timer.addEventListener(TimerEvent.TIMER, internalCallback)
timer.start()
function internalCallback(e:TimerEvent):void
{
try
{
// do something that could cause an error
}
catch (e:Error)
{
errorInConsumerScope.message = e.message
throw errorInConsumerScope
}
}
现在我可以将stacktrace返回到调用代码中:
Error: Error #1009: Cannot access a property or method of a null object reference.
at TestClass()[/[path-to-source-file]/TestClass.as:10]
at Main()[/[path-to-source-file]/Main.as:9]
完整的要点是一种可能的解决方案是在使用者线程/作用域中预先创建一个错误对象
var errorInConsumerScope:Error = new Error()
var timer:Timer = new Timer(1000, 1)
timer.addEventListener(TimerEvent.TIMER, internalCallback)
timer.start()
function internalCallback(e:TimerEvent):void
{
try
{
// do something that could cause an error
}
catch (e:Error)
{
errorInConsumerScope.message = e.message
throw errorInConsumerScope
}
}
现在我可以将stacktrace返回到调用代码中:
Error: Error #1009: Cannot access a property or method of a null object reference.
at TestClass()[/[path-to-source-file]/TestClass.as:10]
at Main()[/[path-to-source-file]/Main.as:9]
完整的要点是有趣的事情
:
将错误的调用堆栈以字符串形式返回到调用时
错误构造
据此,stacktrace按预期工作。错误是在事件处理程序中构造的,该事件处理程序由timer tick事件调用
在第二个示例中,您创建了要在TestClass的构造函数中调度的错误。因此,stacktrace将显示到TestClass构造函数的链。有趣的事情
:
将错误的调用堆栈以字符串形式返回到调用时
错误构造
据此,stacktrace按预期工作。错误是在事件处理程序中构造的,该事件处理程序由timer tick事件调用
在第二个示例中,您创建了要在TestClass的构造函数中调度的错误。因此,stacktrace将显示到TestClass构造函数的链。您可能需要一个通用解决方案。我将使用断点和对象检查进行单元测试和适当的调试。但这里有另一个想法: 测试类:
package {
import flash.events.TimerEvent;
import flash.utils.Timer;
public class TestClass {
public function TestClass(userCallback : Function, fail : Function) {
var timer : Timer = new Timer(1000, 1);
timer.addEventListener(TimerEvent.TIMER, internalCallback);
timer.start();
function internalCallback(e : TimerEvent):void {
try {
var nullProperty : String;
nullProperty.length;
} catch (e:Error) {
fail();
return;
}
userCallback();
}
}
}
}
主要内容:
输出:
Exception fault: Error: Something went wrong.
at Function/<anonymous>()[Main.as:8]
at Function/TestClass/$construct/internalCallback()[TestClass.as:16]
at flash.utils::Timer/_timerDispatch()
at flash.utils::Timer/tick()
你可能会要求一个通用的解决方案。我将使用断点和对象检查进行单元测试和适当的调试。但这里有另一个想法: 测试类:
package {
import flash.events.TimerEvent;
import flash.utils.Timer;
public class TestClass {
public function TestClass(userCallback : Function, fail : Function) {
var timer : Timer = new Timer(1000, 1);
timer.addEventListener(TimerEvent.TIMER, internalCallback);
timer.start();
function internalCallback(e : TimerEvent):void {
try {
var nullProperty : String;
nullProperty.length;
} catch (e:Error) {
fail();
return;
}
userCallback();
}
}
}
}
主要内容:
输出:
Exception fault: Error: Something went wrong.
at Function/<anonymous>()[Main.as:8]
at Function/TestClass/$construct/internalCallback()[TestClass.as:16]
at flash.utils::Timer/_timerDispatch()
at flash.utils::Timer/tick()
这就是解决方案的要点,所以如果错误是在正确的时候产生的,那么它们是非常方便的事情;您可以从多个位置注册相同的侦听器函数。当我正确理解您的操作时,您的解决方案将为每个侦听器注册创建一个空错误。空对象实际上不是我们想要的。我所看到的最干净的解决方案是对不同的客户端使用不同的回调,这样Flash错误就可以很容易地与侦听器注册上下文相匹配。很容易失去追溯到创建者的能力。您所需要做的就是从代码中获得一个级别的间接寻址,如示例中所示,并且您不知道创建调用来自何处。@Brian我不明白为什么在抛出大量默认错误时需要生成新错误。在你的问题中的例子中,它甚至显示了行号。堆栈跟踪也在做它的工作。但是,在您的回答中,抛出的错误并没有告诉我错误真正在哪一行。也许只是我,我已经看到了错误堆栈跟踪的方法。@在现实世界中,问题并不总是像空指针那样简单,问题可能是由TestClass的创建者提供的参数引起的。在这种情况下,查看是谁创建了TestClass比flash player子系统的哪个部分称为Callback更有价值,这是解决方案的重点,因此如果错误是在正确的时间创建的,那么它们是非常方便的事情;您可以从多个位置注册相同的侦听器函数。当我正确理解您的操作时,您的解决方案将为每个侦听器注册创建一个空错误。空对象实际上不是我们想要的。我所看到的最干净的解决方案是对不同的客户端使用不同的回调,这样Flash错误就可以很容易地与侦听器注册上下文相匹配。很容易失去追溯到创建者的能力。您所需要做的就是从代码中获得一个级别的间接寻址,如示例中所示,并且您不知道创建调用来自何处。@Brian我不明白为什么在抛出大量默认错误时需要生成新错误。在你的问题中的例子中,它甚至显示了行号。堆栈跟踪也在做它的工作。但是,在您的回答中,抛出的错误并没有告诉我错误真正在哪一行。也许只是我,我已经看到了错误堆栈跟踪的方法。@在现实世界中,问题并不总是像空指针那样简单,问题可能是由TestClass的创建者提供的参数引起的。在那c
ase与flash player子系统的哪个部分调用Callback相比,查看是谁创建了TestClass更有价值。感谢您的回答,但是这个解决方案仍然只是从计时器/滴答声函数的角度讲述了这个故事。在错误源超出范围后很长时间内,可能会从浏览器/flash播放器调用Tick。我感兴趣的是从Main开始作用域链/堆栈跟踪的解决方案。fail方法是一个闭包,只要有引用,它就会维护上下文。您可以删除Main的实例,但它不会被垃圾收集,因为闭包上有一个引用需要Main的上下文。你能检查一下吗?clojure不是问题所在,clojure确实拥有作用域等,但变量作用域不是问题所在。我的问题与发生错误时给出的堆栈跟踪有关。在异步代码中,堆栈跟踪从Timer/tick开始,但这并没有说明是谁创建了实际的类或函数。我感兴趣的是一个解决方案,它可以从主类的角度显示谁实际创建了计时器。fail方法在Main中创建,但从浏览器事件队列线程调用。因此,当它抛出错误时,堆栈跟踪将从浏览器的角度显示。简言之:大多数时候,我对浏览器的角度不感兴趣,我想知道:我的代码的哪一部分创建了失败的东西。谢谢你的回答,但是这个解决方案仍然只是从计时器/滴答声功能的角度讲述了这个故事。在错误源超出范围后很长时间内,可能会从浏览器/flash播放器调用Tick。我感兴趣的是从Main开始作用域链/堆栈跟踪的解决方案。fail方法是一个闭包,只要有引用,它就会维护上下文。您可以删除Main的实例,但它不会被垃圾收集,因为闭包上有一个引用需要Main的上下文。你能检查一下吗?clojure不是问题所在,clojure确实拥有作用域等,但变量作用域不是问题所在。我的问题与发生错误时给出的堆栈跟踪有关。在异步代码中,堆栈跟踪从Timer/tick开始,但这并没有说明是谁创建了实际的类或函数。我感兴趣的是一个解决方案,它可以从主类的角度显示谁实际创建了计时器。fail方法在Main中创建,但从浏览器事件队列线程调用。因此,当它抛出错误时,堆栈跟踪将从浏览器的角度显示。简言之:大多数时候,我对浏览器的角度不感兴趣,我想知道:我的代码的哪一部分创建了失败的东西。