イベントキャプチャとイベントバブリング

イベントハンドラーを最小化するには、イベントキャプチャとイベントバブリングを使用します。

ActionScript 3.0 のイベントモデルでは、イベントキャプチャとイベントバブリングという概念が導入されています。イベントバブリングの利点を活用すると、ActionScript コードの実行時間を最適化するうえで役立ちます。パフォーマンスを改善するには、複数のオブジェクトではなく、1 つのオブジェクトでイベントハンドラーを登録します。

例えば、ユーザーができるだけ速くりんごをクリックしてつぶす必要があるゲームの作成を考えてみましょう。このゲームでは、クリックするとりんごが画面から消え、ユーザーの得点が加算されます。りんごが送出する MouseEvent.CLICK イベントを監視するには、次のコードを記述することができます。

const MAX_NUM:int = 10; 
var sceneWidth:int = stage.stageWidth; 
var sceneHeight:int = stage.stageHeight; 
var currentApple:InteractiveObject; 
var currentAppleClicked:InteractiveObject; 
  
for ( var i:int = 0; i< MAX_NUM; i++ ) 
{ 
    currentApple = new Apple(); 
    currentApple.x = Math.random()*sceneWidth; 
    currentApple.y = Math.random()*sceneHeight; 
    addChild ( currentApple ); 
     
    // Listen to the MouseEvent.CLICK event 
    currentApple.addEventListener ( MouseEvent.CLICK, onAppleClick ); 
} 
  
function onAppleClick ( e:MouseEvent ):void 
{ 
    currentAppleClicked = e.currentTarget as InteractiveObject; 
    currentAppleClicked.removeEventListener(MouseEvent.CLICK, onAppleClick ); 
    removeChild ( currentAppleClicked ); 
}

このコードでは、各 Apple インスタンスで addEventListener() メソッドを呼び出します。また、りんごがクリックされると、 removeEventListener() メソッドを使用して各リスナーが削除されます。ただし、ActionScript 3.0 のイベントモデルは、一部のイベントに対してキャプチャフェーズおよびバブリングフェーズを提供し、親 InteractiveObject からそれらを監視できるようにします。その結果、上述のコードを最適化し、 addEventListener() メソッドおよび removeEventListener() メソッドの呼び出し回数を最小化することが可能になります。次のコードでは、キャプチャフェーズを使用して親オブジェクトからイベントを監視します。

const MAX_NUM:int = 10; 
var sceneWidth:int = stage.stageWidth; 
var sceneHeight:int = stage.stageHeight; 
var currentApple:InteractiveObject; 
var currentAppleClicked:InteractiveObject; 
var container:Sprite = new Sprite(); 
  
addChild ( container ); 
  
// Listen to the MouseEvent.CLICK on the apple's parent 
// Passing true as third parameter catches the event during its capture phase 
container.addEventListener ( MouseEvent.CLICK, onAppleClick, true ); 
  
for ( var i:int = 0; i< MAX_NUM; i++ ) 
{ 
    currentApple = new Apple(); 
    currentApple.x = Math.random()*sceneWidth; 
    currentApple.y = Math.random()*sceneHeight; 
    container.addChild ( currentApple ); 
} 
  
function onAppleClick ( e:MouseEvent ):void 
{ 
    currentAppleClicked = e.target as InteractiveObject; 
    container.removeChild ( currentAppleClicked ); 
}

このコードは単純化されていて、はるかに最適化されています。親コンテナで addEventListener() メソッドを 1 回呼び出すだけです。リスナーは Apple インスタンスに登録されなくなるので、りんごがクリックされたときに Apple インスタンスを削除する必要はありません。イベントの反映を中止することで、 onAppleClick() ハンドラーをさらに最適化できます。これにより、それ以上のイベントの反映を防ぐことができます。

function onAppleClick ( e:MouseEvent ):void 
{ 
    e.stopPropagation(); 
    currentAppleClicked = e.target as InteractiveObject; 
    container.removeChild ( currentAppleClicked ); 
}

バブリングフェーズはイベントのキャッチにも使用できます。そのためには、 addEventListener() メソッドの 3 つ目のパラメーターとして false を渡します。

// Listen to the MouseEvent.CLICK on apple's parent 
// Passing false as third parameter catches the event during its bubbling phase 
container.addEventListener ( MouseEvent.CLICK, onAppleClick, false );

キャプチャフェーズパラメーターのデフォルト値は false なので、省略できます。

container.addEventListener ( MouseEvent.CLICK, onAppleClick );