2

我一直在嘗試提供更好時,一個錯誤的異步代碼發生在AS3調試信息報告。AS3錯誤從事件回調

至於是默認的,拿在那裏我強迫一個空指針在計時器回調(github gist),我得到以下堆棧跟蹤回控制檯上的情況下,錯誤報告不佳的例子:

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() 

這告訴我很少有關定時器回調如何實際鏈接到我的代碼。

的問題是:我怎樣才能獲得什麼代碼創建的回調信息?

我已經加入我下面的解決方案之一。我很想看看這是否可以改進。

回答

0

一個可能的解決方案是在消費「線程」預先創建Error對象/「範圍」

 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 
      } 
     } 

現在,這給了我堆棧跟蹤回到我的調用代碼:

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] 

完整的要點是here

0

有趣的事情。

The doc to Error.getStackTrace() says

返回錯誤的調用堆棧在 構造錯誤

按照這個時間的字符串,該堆棧跟蹤按預期工作。該錯誤是由您的事件處理程序構造的,由定時器tick事件調用。

在您所創建的錯誤你的第二個例子中的TestClass的構造函數來發送。所以你的stacktrace會顯示鏈到TestClass的構造函數。

+0

這就是解決方案的角度來看,這樣的錯誤是很方便的事情,如果他們在適當的時候創建;) –

+1

您可以從多個位置註冊相同的偵聽器功能。您的解決方案將爲每個聽衆註冊創建一個(空)錯誤,當我明白您的要做什麼時。空物體實際上並不是我們想要的。我看到的最乾淨的解決方案是針對不同的客戶端使用不同的回調,以便Flash錯誤可以輕鬆地與聽衆註冊上下文相匹配。 –

+0

失去跟蹤創建者的能力非常容易。你所需要做的就是從你的代碼中獲得一個間接級別(就像在這個例子中那樣),而你對創建調用來自哪裏卻一無所知。 –

0

你可能問一個通用的解決方案。我會去使用單元測試和適當的調試,使用斷點和對象檢查。但這裏的另一個想法:

的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(); 
      } 
     } 
    } 
} 

主營:

package { 
    import flash.display.Sprite; 

    public class Main extends Sprite { 
     public function Main() { 
      new TestClass(
       function() : void { trace('Call me back when your done.'); }, 
       function() : void { throw new Error('Something went wrong.'); } 
      ); 
     } 
    } 
} 

輸出:

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() 
+0

感謝您的答案更有價值,但該解決方案仍然只從Timer/tick的角度講述故事()函數。在錯誤源超出範圍之後的很長時間內,瀏覽器/ Flash播放器會調用Tick。我感興趣的是在Main上啓動scope-chain/stack-trace的解決方案。 –

+0

'fail()'方法是一個閉包,只要有引用就保持它的上下文。你可以移除Main的實例,但它不會被垃圾收集,因爲在需要'Main'的上下文的閉包上有一個引用。你能檢查一下嗎? –

+0

clojure不是問題,clojure的確是保持範圍等等,但變量範圍不是問題。我的問題涉及發生錯誤時給出的堆棧跟蹤。在異步代碼中,堆棧跟蹤從Timer/tick()開始,但沒有說明誰創建了實際的類或函數。我對解決方案感興趣,它向我展示了誰是從Main類的角度實際創建Timer的人。 fail()方法在Main中創建,但是從瀏覽器事件隊列線程調用。所以當它拋出一個錯誤時,將從瀏覽器的角度顯示堆棧跟蹤。 –