Introducing the AsyncLoop class

 

Out of my recent work, I’m especially proud of and excited about the AsyncLoop class. It’s a serious performance enhancer that takes heavy processes and spreads them out over time, preventing stalls and possible lockups. I originally wrote it to deal with a for loop that contained a complex process and iterated 1000 times. Needless to say, the beach ball made an extended stay each time the loop ran. After implementing AsyncLoop, the beach ball disappeared and animations played smooth throughout.

AsyncLoop works around a timer limit. The developer sets the maximum number of milliseconds to loop through the process function. Once the timer exceeds that limit, it carries over to the next frame and repeats. The loop can be ended a number of ways, providing great flexibility. A limit can be placed on the loop count, mimicking common for loop usage. The loop can return the AsyncLoopAction.BREAK constant. When using that method, AsyncLoopAction.CONTINUE is used to tell the loop to continue to the next tick. Each loop provides analytics, keeping track of its duration, loop count, and frame count. Here are two ways you can use it:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// new AsyncLoop(callback:Function, countLimit:int = -1, timerLimit:int = 20);
var loop:AsyncLoop = new AsyncLoop(tick, 1000);
 
loop.addEventListener(Event.OPEN, loopOpenHandler);
loop.addEventListener(Event.CHANGE, loopChangeHandler);
loop.addEventListener(Event.COMPLETE, loopCompleteHandler);
 
loop.start();
 
function tick():void {
	// heavy process
}
 
function loopOpenHandler(event:Event):void {
	// loop started
}
function loopChangeHandler(event:Event):void {
	// loop carries over to next frame
 
	trace(loop.duration); // incomplete loop running time
	trace(loop.currentCount); // number of callback calls
}
function loopCompleteHandler(event:Event):void {
	// loop complete
 
	trace(loop.duration); // completed loop duration
	trace(loop.frameCount); // frames needed to complete
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
var loop:AsyncLoop = new AsyncLoop(tick);
 
loop.start();
 
stage.addEventListener(MouseEvent.CLICK, clickHandler);
stage.addEventListener(MouseEvent.DOUBLE_CLICK, doubleClickHandler);
 
function tick():String {
	// heavy process
 
	if (loopShouldEnd) {
		return AsyncLoopAction.BREAK;
	}
 
	return AsyncLoopAction.CONTINUE;
}
 
function clickHandler(event:MouseEvent):void {
	if (loop.running) {
		loop.pause();
	} else {
		loop.start();
	}
}
function doubleClickHandler(event:MouseEvent):void {
	loop.cancel();
}

I’m really happy with the class and how far it has come since its original form as fLoop. As always, the source code is on GitHub, so take it and run! If you find it useful, feel free to share how you used it, or simply let me know what you think.

10 replies

  1. This looks like a fantastic class, thanks for the hard work! :)

  2. The sync action should continue through out the menu restart void. Fix the handler for the mouse event so the loop event frames into the duration of the string.

  3. @Jeff — …what?

  4. Great work as always! DestroyFramework is really starting to shape up!

  5. Thanks, Jackson! It’s coming along great. I’ve been sifting through my old framework, improving the classes, formatting them correctly and commenting. I’m having a blast!

  6. @jonnie I thought what I said was pretty simple…you know, de-monetize the function to loop the complete handler, that would speed up the process to carry over the event change callback.

  7. @Jeff — Could you provide example code?

  8. @jonnie No, I dont need to prove amything to you.

  9. @Jeff — I’m asking for example code because I still don’t understand.

    Can anyone else can explain what Jeff means?

  10. I’m pretty sure Jeff is trying to say ‘nice work, thanks for sharing’

Reply