package { import flash.errors.ScriptTimeoutError; import flash.events.Event; import flash.events.EventDispatcher; import flash.display.Shape; /** * Calculates the factorial of a number as an * asynchronous operation. */ public class Factorial extends EventDispatcher { // ENTER_FRAME events dispatched by a composed DisplayObject // instance; one can be used for all Factorial instances private static var enterFrameDispatcher:Shape = new Shape(); /** * Final factorial value after run() completes and * an Event.COMPLETE event is dispatched. */ public var result:uint = 0; // reference to the number from which to get a factorial private var n:uint; // reference to the first recursive object private var rootOp:FactorialOp; /** * Constrctor for new Factorial instances. * @param n The number from which a factorial is calculated. */ public function Factorial(n:uint) { this.n = n; } /** * Starts the factorial operation. */ public function run():void { // initialize the root operation rootOp = new FactorialOp(n); // set up ENTER_FRAME loop enterFrameDispatcher.addEventListener(Event.ENTER_FRAME, loopHandler, false, 0, true); // call the first iteration immediately loopHandler(null); } // ENTER_FRAME loop for asynchronous processing private function loopHandler(event:Event):void { try { // attempt to complete the call // if being delayed, an error will be thrown result = rootOp.call(); // remove ENTER_FRAME event handler enterFrameDispatcher.removeEventListener(Event.ENTER_FRAME, loopHandler, false); // signal to listeners that processing is complete // and the results value is available dispatchEvent(new Event(Event.COMPLETE)); }catch(err:ScriptTimeoutError){ // waiting for next frame } } } } import flash.errors.ScriptTimeoutError; class FactorialOp { private var n:uint; // retained number to multiply private var recursiveOp:FactorialOp; // object used as recursive call // indicates whether or not this // instance has thrown an error // durring processing; every instance // will throw once private var interrupted:Boolean = false; /** * Constructor for new FactorialOp instances. */ public function FactorialOp(n:int) { this.n = n; } /** * Executes factorial logic and returns a result. */ public function call():uint { // only run block if not already run // recursiveOp will only be defined if // this block has completed beforehand if (!recursiveOp){ // escape condition: if (!interrupted){ interrupted = true; throw new ScriptTimeoutError("yield"); } // validate: if (n == 0) return 1; // process: // existence of recursiveOp indicates // completion of this code block recursiveOp = new FactorialOp(n - 1); } // attempt to call recursive object // this may throw an error at which // point it will be tried again var result:uint = recursiveOp.call(); // if successful, clean up instance recursiveOp = null; // return result to parent caller return n * result; } }