相继

发布于 07-29 06:00 字数 5533 浏览 11 评论 0原文

如果没有 for 循环,我很难让某些事情一遍又一遍地发生。 看看这个:

package {

    import flash.display.Sprite;
    import flash.events.Event;

    public class Main extends Sprite {

        public function Main() {

            addEventListener("done", caller);

            caller();            

        }

        public function caller(e:Event = null):void {

            trace("hello!");

            dispatchEvent(new Event("done"));

        }

    }

}

唱这个会给你一个“错误#2094:事件调度递归溢出”。 真的很快。 它将显示事件调度程序和 caller() 在它们内部被调用,嵌套直到错误发生。

我想做的是这样的: “当 caller() 完成后,再次调用它” 不是: “在完成之前调用 caller()”

现在,在人们开始建议使用计时器来猜测需要多长时间或使用 ENTER_FRAME 之前,此 caller() 不会有任何图形数据,也不会连接到 Sprite 和每次通话完成所需的时间可能会有很大差异。 我真的在寻找一种仅在它完全完成后才运行它的方法。

感谢您的帮助。


谢谢你的回复。 我使用了计时器,但仍然可能因调用过多和计时器间隔过短而溢出。 因此,我简化并尝试制作一个基于事件的 for 循环类(类似于 for 循环的类,但具有事件以避免吞噬所有资源)解决方案是调用该函数,在其完成时调用计时器; 计时器完成后,再次调用该函数并将它们相互弹开。 基本上:

call function
wait
call function
wait etc.

即使计时器设置为 0 并且它会冻结 swf,直到调用所有函数,该函数也会在再次运行之前完成。

尝试一下:

package {

import flash.display.Sprite;

public class Efl extends Sprite { // the main class

    public function Efl() {

        // make four functions...
        function init (o:Object):void { // akin to the first part of the for loop

            o.value = 0;

        }

        function condition(o:Object):Boolean { // like the condition portion of the for loop

            if (o.value <= 100) {

                return (true);

            } else {

                return (false);

            }

        }

        function next(o:Object):void { // the increment part of a for loop

            o.value++;

        }

        function statements(o:Object):void { // the body of the for loop

            trace(o.value);

        }

        // put the four functions in one new EventForLoop
        var test1:EventForLoop = new EventForLoop(init, condition, next, statements, 1); // delay is 1 ms
        test1.start(); // set it into motion

        // do it again all in one line - not pretty but it works
        var test2:EventForLoop = new EventForLoop(
            function (o:Object):void { o.value = 0; },
            function (o:Object):Boolean { if (o.value <= 50) return (true); else return (false); },
            function (o:Object):void { o.value++ },
            function (o:Object):void { trace("> " + o.value) },
            20); // delay in 100ms

        test2.start(); // start it up

        // if you try this out, the two will run intertwined since the delays are different.

    }

} 
}

这是运行循环的类:

package {

import flash.events.EventDispatcher;
import flash.events.Event;
import flash.events.TimerEvent;
import flash.utils.Timer;

public class EventForLoop extends EventDispatcher {

    // functions to call when simulating the for loop
    private var initializer:Function; // is run once at the start of the loop
    private var condition:Function; // returns boolean to tell the loop to continue or not
    private var step:Function; // the function that runs after the loop is complete
    private var statements:Function; // the actual body of the loop

    private var timeout:Timer; // the timer to avaoid overflows

    private var operator:Object = new Object(); // this is an object to hold and pass values across all the sub loop functions. it is the parameter passed to all four functions

    // some event constants
    static const NEXT:String = new String("EFLNext"); 
    static const DONE:String = new String("EFLDone");


    // constructor just loads vars and sets up timer
    public function EventForLoop (init:Function, cond:Function, stepper:Function, stat:Function, delay:Number = 0) {

        initializer = init;
        condition = cond;
        step = stepper;
        statements = stat;

        timeout = new Timer(delay, 1);

    }

    // the mail loop function...
    private function next(e:Event = null):void {

        // Try this and the lone afte the loop:
        // trace ("start statements");

        if (condition.call(null, operator)) { // if the condition is still true...

            statements.call(null, operator); // do the body statements of the loop
            step.call(null, operator); // increment
            dispatchEvent(new Event(EventForLoop.NEXT)); // dispatch the event so that thw wait can start

        } else { // condition returns false??

            dispatchEvent(new Event(EventForLoop.DONE)); // tell the event dispatcher the loop is done
            removeEventListener(EventForLoop.NEXT, wait); // stop event listeners
            timeout.removeEventListener(TimerEvent.TIMER_COMPLETE, next); 

        }

        // trace ("finish statements\n");
        // this line and the one before the if() will show that the functcion ends before starting again, even if the Timer wait 0ms

    }

    // very simple function that waits and ten triggers the  loop again
    private function wait(e:Event):void {

        timeout.reset();
        timeout.start();

    }

    // metod used to set the loop running
    public function start():void {

        initializer.call(null, operator); // use the initioalizer to set the operator Object
        addEventListener(EventForLoop.NEXT, wait); // when the loops done, wait
        timeout.addEventListener(TimerEvent.TIMER_COMPLETE, next); // when done waiting, loop again

        next(); //do the first loop

    }

} 

}

I'm having trouble making something happen over and over without a for loop. Take a look at this:

package {

    import flash.display.Sprite;
    import flash.events.Event;

    public class Main extends Sprite {

        public function Main() {

            addEventListener("done", caller);

            caller();            

        }

        public function caller(e:Event = null):void {

            trace("hello!");

            dispatchEvent(new Event("done"));

        }

    }

}

sing this will get you an "Error #2094: Event dispatch recursion overflow." really fast. It will show that the event dispatcher and caller() are getting called inside of them selves, nesting until the error happens.

What I want to do is this:
"When caller() is done, call it again"
not:
"call caller() before it finishes"

Now, before people start suggesting using a timer to guess how long it will take or use ENTER_FRAME, This caller() will not have any graphic data and won't be connected to a Sprite and the time it takes to finish may vary greatly from call to call. I'm really looking for a way to run it only after it has completely finished.

Thanks for your help.


Thank you for your responses. I used Timer and still could overflow with too many calls and too short a timer interval. So I simplified and tried to just make an Event based for loop class (A class that operates like a for loop, but with events to avoid gobbling up all the resources) The solution was to call the function, on it's completion call the timer; on the timer's completion call the function again and bounce them off of each other. Basically:

call function
wait
call function
wait etc.

Even if the timer is set to 0 and it freezes the swf until the all the functions are called, the function will complete before running again.

try it out:

package {

import flash.display.Sprite;

public class Efl extends Sprite { // the main class

    public function Efl() {

        // make four functions...
        function init (o:Object):void { // akin to the first part of the for loop

            o.value = 0;

        }

        function condition(o:Object):Boolean { // like the condition portion of the for loop

            if (o.value <= 100) {

                return (true);

            } else {

                return (false);

            }

        }

        function next(o:Object):void { // the increment part of a for loop

            o.value++;

        }

        function statements(o:Object):void { // the body of the for loop

            trace(o.value);

        }

        // put the four functions in one new EventForLoop
        var test1:EventForLoop = new EventForLoop(init, condition, next, statements, 1); // delay is 1 ms
        test1.start(); // set it into motion

        // do it again all in one line - not pretty but it works
        var test2:EventForLoop = new EventForLoop(
            function (o:Object):void { o.value = 0; },
            function (o:Object):Boolean { if (o.value <= 50) return (true); else return (false); },
            function (o:Object):void { o.value++ },
            function (o:Object):void { trace("> " + o.value) },
            20); // delay in 100ms

        test2.start(); // start it up

        // if you try this out, the two will run intertwined since the delays are different.

    }

} 
}

Here is the Class that runs the loop:

package {

import flash.events.EventDispatcher;
import flash.events.Event;
import flash.events.TimerEvent;
import flash.utils.Timer;

public class EventForLoop extends EventDispatcher {

    // functions to call when simulating the for loop
    private var initializer:Function; // is run once at the start of the loop
    private var condition:Function; // returns boolean to tell the loop to continue or not
    private var step:Function; // the function that runs after the loop is complete
    private var statements:Function; // the actual body of the loop

    private var timeout:Timer; // the timer to avaoid overflows

    private var operator:Object = new Object(); // this is an object to hold and pass values across all the sub loop functions. it is the parameter passed to all four functions

    // some event constants
    static const NEXT:String = new String("EFLNext"); 
    static const DONE:String = new String("EFLDone");


    // constructor just loads vars and sets up timer
    public function EventForLoop (init:Function, cond:Function, stepper:Function, stat:Function, delay:Number = 0) {

        initializer = init;
        condition = cond;
        step = stepper;
        statements = stat;

        timeout = new Timer(delay, 1);

    }

    // the mail loop function...
    private function next(e:Event = null):void {

        // Try this and the lone afte the loop:
        // trace ("start statements");

        if (condition.call(null, operator)) { // if the condition is still true...

            statements.call(null, operator); // do the body statements of the loop
            step.call(null, operator); // increment
            dispatchEvent(new Event(EventForLoop.NEXT)); // dispatch the event so that thw wait can start

        } else { // condition returns false??

            dispatchEvent(new Event(EventForLoop.DONE)); // tell the event dispatcher the loop is done
            removeEventListener(EventForLoop.NEXT, wait); // stop event listeners
            timeout.removeEventListener(TimerEvent.TIMER_COMPLETE, next); 

        }

        // trace ("finish statements\n");
        // this line and the one before the if() will show that the functcion ends before starting again, even if the Timer wait 0ms

    }

    // very simple function that waits and ten triggers the  loop again
    private function wait(e:Event):void {

        timeout.reset();
        timeout.start();

    }

    // metod used to set the loop running
    public function start():void {

        initializer.call(null, operator); // use the initioalizer to set the operator Object
        addEventListener(EventForLoop.NEXT, wait); // when the loops done, wait
        timeout.addEventListener(TimerEvent.TIMER_COMPLETE, next); // when done waiting, loop again

        next(); //do the first loop

    }

} 

}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

淡淡绿茶香2024-08-05 06:00:19

您可能想尝试 flash .utils.setTimeout()。 将其放在 caller() 的底部并为其自身设置超时。 如果你给它一个非常小的超时间隔,它会在下次 Flash 有机会时异步递归。

或者,ENTER_FRAME 事件将执行或多或少相同的操作(除了极高的帧速率)。 Flash会延迟下一帧的渲染,直到一帧上的所有处理逻辑完成。 此外,Flash 是单线程的,因此可以保证函数的两个副本永远不会同时运行。

You might want to experiment with flash.utils.setTimeout(). Put it at the bottom of caller() and have it set a timeout for itself. If you give it a very small timeout interval, it will asynchronously recurse the next time Flash gets the chance.

Alternatively, an ENTER_FRAME event will do more or less the same thing (except at extremely high framerates). Flash will delay the rendering of the next frame until all the processing logic on one frame has finished. Furthermore, Flash is single-threaded, so you can be guaranteed that two copies of your function will never run simultaneously.

呢古2024-08-05 06:00:19

我有一些与其他一些回复者类似的问题。 您希望多久拨打一次电话? 如果您希望调用在完成后立即重复,则程序的其他部分将没有机会执行。

I've got questions similar to some of the other responders. How often do you want the call to happen? If what you want is for the call to immediately repeat as soon as it finishes, no other part of your program will ever get a chance to execute.

素染倾城色2024-08-05 06:00:19

这是要交作业吗?

如果你不需要 for 循环,那么 while 循环怎么样?

尝试使用计时器可能会起作用,但会变得混乱。 如果您绝对必须使用计时器,那么如果您的函数仍在运行,请将一些布尔标志设置为 true/false。 计时器事件将查看您的函数是否完成,如果是,则再次调用它。

Is this for an assignment?

If you don't want for loops, how about a while loop?

Trying to use timers could work but it gets messy. If you absolutely must user a Timer then have some boolean flag set to true/false if your function is still running. The timer event would see if your function is finished, if so then call it again.

别理我2024-08-05 06:00:19

我会使用enterFrame...Flash是基于帧的...当你的过程完成时,你检查是否还有时间再次调用该函数,如果没有,只需等待下一帧的到来...

addEventListener("enterFrame", loop);
function loop(e) {
   var maxtime=1000/stage.frameRate;
   var t1=getTimer();
   while(getTimer()-t1 < maxtime) {
      myProcess();
   }
}

I would use enterFrame... Flash is frame based... when your process is finished, you check if you still have time for another call to the function, if not, just wait for the next frame to come...

addEventListener("enterFrame", loop);
function loop(e) {
   var maxtime=1000/stage.frameRate;
   var t1=getTimer();
   while(getTimer()-t1 < maxtime) {
      myProcess();
   }
}
寒冷纷飞旳雪2024-08-05 06:00:19

好的,我知道你说的

他的 caller() 不会有任何图形数据,也不会连接到 Sprite

并且

我真的在寻找一种仅在它完全完成后才运行它的方法。

因此,我将解决这些问题,然后告诉您 EnterFrame 是最好的解决方案:)

您不需要图形表示,也不需要访问舞台来使用 Enter Frame 事件侦听器。 您可以简单地执行以下操作:

var s:Shape = new Shape();
s.addEventListener(Event.ENTER_FRAME, caller)

private function caller():void
{
    //do stuff
}

上面我们简单地创建了一个形状来侦听输入帧事件,这就是我们使用它的全部目的。

至于第二部分,当代码在运行时被解释并到达一个函数(在本例中为调用者)时,它不会执行另一个函数或该函数外部的代码行,直到它完成为止。 所以你知道它在完成前一个调用之前永远不会再次执行。

因此,输入框架(或计时器)是您最好/唯一的解决方案。

OK, I know you said

his caller() will not have any graphic data and won't be connected to a Sprite

And

I'm really looking for a way to run it only after it has completely finished.

So I'll address those and then tell you an enterframe is the best solution :)

You don't need a graphical representation, or access to the stage to use a enter frame event listener. You can simply do the following:

var s:Shape = new Shape();
s.addEventListener(Event.ENTER_FRAME, caller)

private function caller():void
{
    //do stuff
}

Above we simple create a shape to listen for the enter frame events, and thats all we use it for.

As for the second part, when code is being interpreted at runtime and it comes to a function, caller in this case, it won't execute another function, or line of code outside that function, until it has finished it. So you know that it will never execute again until it has finished the previous call.

So an enterframe (or a timer) are your best / only solutions.

十雾2024-08-05 06:00:19

您想要做的是在 Caller() 完成时分派一个新事件,然后再次调用调用者。

但是你需要有一个最大循环计数器,否则你只会得到堆栈溢出错误。

不要忘记对事件侦听器使用弱引用,因为它将始终使用未使用的对象来收集垃圾并帮助您的应用程序运行得更流畅+更快。

package {

    import flash.display.Sprite;
    import flash.events.Event;

    public class Main extends Sprite {

        public function Main() {

            addEventListener("Call_ME_AGAIN", callCaller, false, 0, true );


            caller();            

        }


        private var _counter:int = 0;
        private const LOOP_TIMES:int = 100;
        public function caller(e:Event = null):void {

            trace("hello!");

            if (counter != LOOP_TIMES)
            {
              dispatchEvent(new Event("Call_ME_AGAIN"));
              counter++;
            }
            else if (counter == LOOP_TIMES)
            { //reset the counter so it can happen again when you want
              counter = 0;
             }

        }

        public function callCaller(e:Event = null):void {

            e.stopImmediatePropagation();

            caller(null);

        }

    }

}

What you want to do is dispatch a new event when the Caller() finishes that then calls caller again.

But your need to have a max loop counter otherwise you will just get a stack overflow error.

Don't forget to use weak reference to your event listeners, as it will alway unused object to get garbage collected and help your app run smoother + faster.

package {

    import flash.display.Sprite;
    import flash.events.Event;

    public class Main extends Sprite {

        public function Main() {

            addEventListener("Call_ME_AGAIN", callCaller, false, 0, true );


            caller();            

        }


        private var _counter:int = 0;
        private const LOOP_TIMES:int = 100;
        public function caller(e:Event = null):void {

            trace("hello!");

            if (counter != LOOP_TIMES)
            {
              dispatchEvent(new Event("Call_ME_AGAIN"));
              counter++;
            }
            else if (counter == LOOP_TIMES)
            { //reset the counter so it can happen again when you want
              counter = 0;
             }

        }

        public function callCaller(e:Event = null):void {

            e.stopImmediatePropagation();

            caller(null);

        }

    }

}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文