相继
如果没有 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 技术交流群。

发布评论
评论(6)
好的,我知道你说的
他的 caller() 不会有任何图形数据,也不会连接到 Sprite
并且
我真的在寻找一种仅在它完全完成后才运行它的方法。
因此,我将解决这些问题,然后告诉您 EnterFrame 是最好的解决方案:)
您不需要图形表示,也不需要访问舞台来使用 Enter Frame 事件侦听器。 您可以简单地执行以下操作:
var s:Shape = new Shape();
s.addEventListener(Event.ENTER_FRAME, caller)
private function caller():void
{
//do stuff
}
上面我们简单地创建了一个形状来侦听输入帧事件,这就是我们使用它的全部目的。
至于第二部分,当代码在运行时被解释并到达一个函数(在本例中为调用者)时,它不会执行另一个函数或该函数外部的代码行,直到它完成为止。 所以你知道它在完成前一个调用之前永远不会再次执行。
因此,输入框架(或计时器)是您最好/唯一的解决方案。
您想要做的是在 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);
}
}
}
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
您可能想尝试
flash .utils.setTimeout()
。 将其放在caller()
的底部并为其自身设置超时。 如果你给它一个非常小的超时间隔,它会在下次 Flash 有机会时异步递归。或者,ENTER_FRAME 事件将执行或多或少相同的操作(除了极高的帧速率)。 Flash会延迟下一帧的渲染,直到一帧上的所有处理逻辑完成。 此外,Flash 是单线程的,因此可以保证函数的两个副本永远不会同时运行。
You might want to experiment with
flash.utils.setTimeout()
. Put it at the bottom ofcaller()
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.