Event capture and bubbling

Use event capture and bubbling to minimize event handlers.

The event model in ActionScript 3.0 introduced the concepts of event capture and event bubbling. Taking advantage of the bubbling of an event can help you to optimize ActionScript code execution time. You can register an event handler on one object, instead of multiple objects, to improve performance.

As an example, imagine creating a game in which the user must click apples as fast as possible to destroy them. The game removes each apple from the screen when it is clicked and adds points to the user’s score. To listen to the MouseEvent.CLICK event dispatched by each apple, you could be tempted to write the following code:

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

The code calls the addEventListener() method on each Apple instance. It also removes each listener when an apple is clicked, using the removeEventListener() method. However, the event model in ActionScript 3.0 provides a capture and bubbling phase for some events, allowing you to listen to them from a parent InteractiveObject. As a result, it is possible to optimize the code above and minimize the number of calls to the addEventListener() and removeEventListener() methods. The following code uses the capture phase to listen to the events from the parent object:

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

The code is simplified and much more optimized, with only one call to the addEventListener() method on the parent container. Listeners are no longer registered to the Apple instances, so there is no need to remove them when an apple is clicked. The onAppleClick() handler can be optimized further, by stopping the propagation of the event, which prevents it from going further:

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

The bubbling phase can also be used to catch the event, by passing false as the third parameter to the addEventListener() method:

// 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 );

The default value for the capture phase parameter is false , so you can omit it:

container.addEventListener ( MouseEvent.CLICK, onAppleClick );

// Ethnio survey code removed