views:

65

answers:

3

Hi:

I have a class with several methods I must run in an specific order. So, I created a kind of chain where each one calls the next in its last sentence (sometimes with calls, sometimes dispatching events):

internal function a(evt:SwapEvent):void {   //started from custom event
  ...
  b();
}

private function b():void {
  ...
  bTimer = new Timer(bTime*1000,1);
  bTimer.addEventListener(TimerEvent.TIMER, bEnd);
  bTimer.start();
}

private function bEnd(evt:TimerEvent):void {
  bTimer.removeEventListener(TimerEvent.TIMER, bEnd);
  bTimer = null;                    
  c();
}

private function c():void {
  ...
  dispatchEvent(new CustomEvents(CustomEvents.NEXT_FRAME,1));
}
....
private function g():void {
  // tell the second class the sequence finished
}

The problem is at some point and before arriving at last method, I need to run again a sub-sequence, let's say from function c() to e(). And it's causing problems in the form of an increasing delay between functions (I have 2 timers)

I guess the solution is something like this:

a();
b();
...
if (some condition) {
  c();
  ...
  e();
}
...
f();
g();

But, as far as I know, Flash Player doesn't make a synchronous execution. i.e., it doesn't wait until method a() completes to execute b()

Any idea/suggestion on a clean and bullet-proof implementation? This application will run in an endless loop 24x7

Thanks in advance,

+3  A: 

After reading your code properly, yes, you are right. b() gets executed as that line of code is reached.

I might be tempted to create a queue of methods to execute. Execute one, check to see if you have time to execute another before the frame needs updating, and repeat. You can always insert new commands in to the queue at any time, so b() could insert endB() next in the queue.

Both the sequencers at http://www.dpdk.nl/opensource/running-tasks-in-order-with-a-task-based-sequence-manager and http://as3.casalib.org/docs/org_casalib_time_Sequence.html should do what you need. The former might be a bit of overkill as it looks like you need to create individual classes for each of your tasks which may be a little too much overhead. On the other hand the Conditional Tasks look like they are exactly what you need. The latter being simpler in that you can specify methods to execute. However, there doesn't seem to be a built in way to condition the tasks, but that may just be as easy as creating a task that conditionally adds tasks.

It might help to know a bit more how the conditions work.

Other points:

Tail calls are not very efficient in AS. Think of it as adding more to the stack every time you call a method. Once the method returns (even if you don't explicitly use return) the method gets knocked off the stack and the previously called method will continue to execute. So the more tail calls, the bigger the stack and the more to clean up.

As soon you start executing code the player hangs until the code has completely run and execution has returned to the player. You have around a 15 second execution limit before the player will kill your script, so you have to account for that when endlessly executing code. The solution is to execute some code then wait till the next frame to execute more.

You don't have to recreate your Timers, you can create them once as instance variables and just call start. The timers will return execution to the player (if no more method calls are made).

A somewhat simplified version, but I'm sure you get the picture.

Joony
@Joony: Thanks for your time and advice. I agree the problem resides in the stack getting collapsed. And regarding the Timers, I destroyed and created again just as a blind shoot ;-)
hsands
+2  A: 

There are a number of libraries that provide sequenced execution in AS3. Usually they are for performing Animation so they will generally have a bias toward that.

For example, Twease and Tweener will let you do sequenced actions as well as generic animation actions.

Another particularly good sequencing library is included as part of the asapframework ... which has a class called ActionQueue to which you can add TimedAction items. The great thing about TimedAction & ActionQueue is the feature to add an undo method and arguments, if you need to run the sequence backwards.

Using sequencers is a lot simpler than setting up a mass of timers manually.

slomojo
@slomojo: I'll really appreciate your example. Have you or any other member tried one of this packages/classes: http://www.dpdk.nl/opensource/running-tasks-in-order-with-a-task-based-sequence-manager or http://as3.casalib.org/docs/org_casalib_time_Sequence.html
hsands
Rolf Vreijdenberger's (dpdk.nl) solution is probably best for you because it's specific to sequencing generic actions, he's also provided a good set of examples. -- all the options in my answer and in the two links you've added in your comment, will do what you need, the only difference is in the other things they do, and perhaps in performance / ease of use.
slomojo
+1  A: 

i don't really understand your question. actionscript is synchronous in general (except for some AIR functions that can be executed asynchronously), but a timer is asynchronous in the sense that your code will not pause and wait for the timer to complete before continuing the main thread.

if you want your methods to only execute following the completion of a timer, use the timer event TIMER_COMPLETE event listener.

TheDarkInI1978
@TDI1978: Make a simple test (Or I can send you my example if you want). Create a class with just 2 methods calls: res = factorial(n); showRes(n,res); and set res=0. In my desktop computer (Mac, 2.4 GHz Intel Core 2 Duo, 4 GB DDR2) I only need to set n=50 to see in the text field: !50 = 0. What clearly shows the second method was executed before the first one ended. No Timers, Loaders or any other asynchronous class. Regarding Timer, as I set the repeatCount property=1, I guess TimerEvent.TIMER is the same as TimerEvent.TIMER_COMPLETE. Isn't it?
hsands
@hsands. "What clearly shows the second method was executed before the first one ended". No, that's not how flash works. Your example is not totally clear to me, though. Can you post code or pseudo code to the example above to make sure we are on the same page?
Juan Pablo Califano
@JPC: Just take a look at the pseudo-code in the second part of my question. Do you mean that b() won't be executed until a() completes? Let's assume two scenarios: 1. There isn't any asynchronous call inside a() 2. There's a Timer in a()
hsands
@hsands. Yes, I meant that b() won't be called until a() completes. But maybe we have a terminology issue here. By *completes* I mean *returns*. So b() wont' be called until a() returns. That is, except you somehow call it from *within* a(); this could be the case if you dispatched a synchronous event, handled by some other code that calls b() in turn. But that's a different funciton application of b() (which is just a fancy way of saying you called b() from somewhere else ;) )
Juan Pablo Califano
@JPC: Ok, I understand. In scenario 1, completes = return and in scenario 2 probably they aren't the same because a() can return while an asynchronous proccess is still in course.
hsands