简体   繁体   中英

Create delay in ActionScript 3 function

I have a function in Adobe Flex 4 (ActionScript 3) that accepts an object and returns an ArrayCollection...

If a certain global variable is set to true, I want the function to delay itself for 3 seconds before running. Otherwise I want the function to run as normal.

The problem is, if I use a Timer, that timer calls a separate function, and that function cannot return anything to my calling function, nor can the function it calls accept any parameters, so it's not like I can call my own function recursively after the TimerComplete event fires... And a recursive call wouldn't work anyway, because it would return the ArrayCollection to the timer-result function, not to the original calling function...

I need a delay within the function, not a delay that causes me to go outside that function. But I cannot figure out how to do it.

Something like this is what I need to do:

private function createArrayCollection(myObject:Object):ArrayCollection {

    var myArrayCollection:ArrayCollection = new ArrayCollection();

    if (globalWaitBoolean) {
        //delay here for 3 seconds, somehow
    }

    //Here I do the stuff that uses the info in myObject to figure out what to
    //put into the ArrayCollection I want to return

    return (myArrayCollection);
}

So... Any ideas on how to accomplish this without calling an external Timer function that cannot return an object back to my original function?

Thanks,

The way you want it you will have your whole application to lag for 3 seconds, unresponsive to any user input and external events. But it is possible, sure:

import flash.utils.getTimer;

private function createArrayCollection(myObject:Object):ArrayCollection
{
    var myArrayCollection:ArrayCollection = new ArrayCollection;

    if (globalWaitBoolean)
    {
        var waitUntil:int = getTimer() + 3000;

        // Method getTimer() returns time in ms passed since app start.
        // So you just have to wait until it is greater than appointed time.
        while (getTimer() < waitUntil)
        {
            // Do nothing.
        }
    }

    return (myArrayCollection);
}

Still, if you want to do it in a correct way of doing it:

import flash.utils.setTimeout;

private function callerMethod():void
{
    // Blah blah blah.
    // ...
    // Finally.
    createArrayCollection(sourceData, asyncResult);
}

private function createArrayCollection(myObject:Object, handler:Function):void
{
    var result:ArrayCollection = new ArrayCollection;

    if (globalWaitBoolean) setTimeout(handler, 3000, result);
    else handler(result);
}

private function asyncResult(source:ArrayCollection):void
{
    // The rest of your processing code.
}

Normal (synchronous) code flow would not return until the value is prepared, so should you desire to actually wait for 3 seconds while not allowing your app to do anything, use getTimer() approach from @Organis's answer. If you'll go for an asynchronus result, you'll need to face and overcome some more problems.

First, when do you expect your returned ArrayCollection to actually arrive. Speaking of code design, asynchronous code requires a whole lot of assumptions, thread safety etc etc, and even while AS3/Flash does not have true multithreading unless you count Worker s, the code flow with events is not as obvious. So, whoever called your createArrayCollection() MUST NOT expect value returned from it right away. So, speaking about your direct question, NO, you can't avoid timers of some sort if you desire a responsive application. But you can use them with an approach that would involve an indirectly returned result.

Second, whether there might be concurring requests for more array collections from objects if your app would require these - you have to prepare for any kind of interference that might be caused by this. Say your function is triggered by a button click - what if that button would get clicked more than once in 3 seconds?

Third, actual route to processing code is not direct with asynchronous return. You need either a callback, an event handler (which is essentially a semi-native callback), a code that periodically checks for value presence (enter frame handler, etc) or a similar trick to gather the value that's returned asynchronously, and then transfer it to any relevant code that would process it further. Therefore, you would need to design an interface capable of receiving complex data (source object forward, array collection backward) and then carefully test it against all the possible cases and flaws.

An example of implementing all that is very long, I'll try to outline it somehow. Ler's assume you have a sort of "server" class that accepts requests for data and processes it synchronously (no wait) or asynchronously (wait). It accepts a source object of type "T" and provides a newly created object of type ArrayCollection , supplied as a parameter to whatever callback function sent to it. Also it accepts a delay (a simple way to show sync/async return would be a boolean, but why not getting an int?) as a parameter, and guarantees (to the extent of event model limitations) that after this delay the callback will be called ASAP. The architecture will then look like this:

class Processor {
    Dictionary requests; // here all the requests that are delayed will be stored
    public function dpr(source:T,callback:Function,delay:int=0):void{...}
    // creates requests and stores them
    private function syncProcess(source:T):ArrayCollection {...}
    // whatever routine you want to get variably delayed
    private function processTimeout(e:Event=null):void {...}
    // processes events from "setTimeout()" and calls callbacks
}

Note that asynchronous approach forced to create three more entities than a synchronous one. First is the request holding structure (the dictionary here), second is timeout event handler, third is whatever callback you'll desire to get called when the data is ready. The code flow would go like this:

Synchronous call would result in the callback directly called from within the class: request -> processTimeout -> syncProcess() -> callback . Asynchronous call will have the callback called from within Timer::timerComplete event handler via setTimeout called within request , with data that originally came from request stored in requests .

You could use an embedded/inline function:

private function createArrayCollection(myObject:Object):ArrayCollection {

    var myArrayCollection:ArrayCollection = new ArrayCollection();

    if (globalWaitBoolean) {
        var milliseconds:int = 3000;
        //delay here for 3 seconds
        setTimeout(function()
        {
            //Here I do the stuff that uses the info in myObject to figure out what to
            //put into the ArrayCollection I want to return
            return (myArrayCollection);
        },
        milliseconds);
    }
    else
    {
        //Here I do the stuff that uses the info in myObject to figure out what to
        //put into the ArrayCollection I want to return
        return (myArrayCollection);
    }
}

The inner function will have access to all local vars of the outer function.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM