TimedForEach Class
I ran into some trouble today with batch processing some files.
I am processing a set of files, but it is possible that some of the supplied files are invalid.
In that case i want to be able to pop up a messagebox and ask the user if he wants to retry, ignore or abort.
A lot of the involved calls have to be processed asynchronously and i have to give control back to the runtime in between calls, so that Flash can update the display (amongst other things).
The obvious solution is a queue that pauses in between calls to the processing routine and that can be paused while waiting for the user input.
This class does exactly that.
/**
* ...
* @author Oliver "gencha" Salzburg
* @version 0.1
*/
package util {
import flash.events.EventDispatcher;
import flash.utils.Timer;
import flash.events.TimerEvent;
/**
* The TimedForEach class enabled you to run a command on an array of items while having full control over the process.
* The class allows for processing of the items in an asychronous environment.
* You can pause the loop and resume it later on.
* A typical application would be pausing the loop while waiting for user input which could manipulate the way the loop behaves.
*/
public class TimedForEach extends EventDispatcher {
/**
* The delay between calls to the item processor
*/
private static const DEFAULT_DELAY:uint = 100;
private var targets_:Array;
private var command_:Function;
private var targetIndex_:int;
private var lastIndex_:int;
private var timer_:Timer;
private var isStalled_:Boolean;
/**
* Default constructor
* @param targets The array that is to be processed.
* The array is not copied and not modified by the class
* @param command The command that is applied to each item in the targes array.
* The function is called with a single target as it's parameter
*/
public function TimedForEach( targets:Array, command:Function ) {
targets_ = targets;
command_ = command;
}
/**
* Start the loop
*/
public function execute():void {
isStalled_ = false;
targetIndex_ = 0;
lastIndex_ = 0;
timer_ = new Timer( DEFAULT_DELAY );
timer_.addEventListener( TimerEvent.TIMER, checkState );
timer_.start();
}
/**
* Stop processing
*/
public function kill():void {
timer_.stop();
}
/**
* Process the next item if possible
* @param event
*/
private function checkState( event:TimerEvent ):void {
if( isStalled_ ) return;
if( targets_.length <= targetIndex_ ) {
dispatchEvent( new TimerEvent( TimerEvent.TIMER_COMPLETE ) );
kill();
return;
}
lastIndex_ = targetIndex_;
command_( targets_[ targetIndex_++ ] );
}
/**
* Pause processing
* @see #resume()
*/
public function stall():void {
isStalled_ = true;
}
/**
* Resume processing
* @see #stall()
*/
public function resume():void {
isStalled_ = false;
}
/**
* Retry the last processed item
*/
public function again():void {
targetIndex_ = lastIndex_;
}
/**
* Resets the loop on the first item in the list
*/
public function reset():void {
targetIndex_ = 0;
lastIndex_ = 0;
}
/**
* Returns an exact copy of the object
* @return An exact copy of the object
*/
public function clone():TimedForEach {
var clone:TimedForEach = new TimedForEach( targets_, command_ );
return clone;
}
/**
* Returns a representation of the object as a string
* @return A representation of the object as a string
*/
override public function toString():String {
return "[object TimedForEach]";
}
}
}
