我无法在没有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()”
现在,在人们开始建议使用计时器猜测需要多长时间或使用ENTER_FRAME之前,此调用者()将不会有任何图形数据,也不会连接到Sprite,并且完成所需的时间可能因呼叫而异。我真的在寻找一种方法,只有在完成后才能运行它。
感谢您的帮助。
感谢您的回复。我使用了Timer,但是仍然会有太多的调用和定时器间隔太短的溢出。所以我简化了并试图创建一个基于循环类的事件(一个类似于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
}
}
}
答案 0 :(得分:1)
您可能想要试验flash.utils.setTimeout()
。把它放在caller()
的底部,让它为自己设置一个超时。如果你给它一个非常小的超时间隔,它将在下次Flash获得机会时异步递归。
或者,一个ENTER_FRAME事件或多或少会做同样的事情(除了极高的帧速率)。 Flash将延迟下一帧的渲染,直到一帧上的所有处理逻辑都完成为止。此外,Flash是单线程的,因此可以保证您的两个函数副本永远不会同时运行。
答案 1 :(得分:1)
我有类似于其他一些响应者的问题。您多久希望拨打一次电话?如果您希望 的电话一旦完成立即重复播放,您的节目的任何其他部分都将无法执行。
答案 2 :(得分:0)
这是作业吗?
如果你不想要循环,那么while循环怎么样?
尝试使用计时器可以工作,但它会变得混乱。如果您绝对必须使用Timer,那么如果您的函数仍在运行,则将一些布尔标志设置为true / false。计时器事件将查看您的功能是否已完成,如果是,则再次调用它。
答案 3 :(得分:0)
我会使用enterFrame ... Flash是基于帧的......当你的过程结束时,你检查你是否还有时间再次调用该函数,如果没有,只需等待下一帧的到来.. 。
addEventListener("enterFrame", loop);
function loop(e) {
var maxtime=1000/stage.frameRate;
var t1=getTimer();
while(getTimer()-t1 < maxtime) {
myProcess();
}
}
答案 4 :(得分:0)
好的,我知道你说过
他的来电者()不会有任何图形数据,也不会连接到精灵
并且
我真的在寻找一种只有在完成后才能运行它的方法。
所以我会解决这些问题,然后告诉你一个enterframe是最好的解决方案:)
您不需要图形表示,也不需要访问舞台即可使用输入帧事件侦听器。您可以简单地执行以下操作:
var s:Shape = new Shape();
s.addEventListener(Event.ENTER_FRAME, caller)
private function caller():void
{
//do stuff
}
上面我们简单地创建一个形状来监听输入框架事件,这就是我们使用它的所有内容。
至于第二部分,当代码在运行时被解释并且它来到一个函数时,在这种情况下调用者,它将不会执行另一个函数或该函数之外的代码行,直到它完成它。所以你知道它在完成上一次调用之前永远不会再执行。
因此,enterframe(或计时器)是您最好/唯一的解决方案。
答案 5 :(得分:0)
你想要做的是在Caller()完成然后再次调用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);
}
}
}