运行 AS3 函数异步化

4
我在学习一些相关的在线教程时遇到了困难,所以来这里问一下。(使用ActionScript 3、Adobe AIR和Flash Professional CS5.5)
我的AS3文档类中有一个非常复杂的函数,我需要异步运行它,以便不会阻止MovieClip本身上的代码(不要问我为什么,它只需要这样)。简而言之,我该如何异步运行这个文档类函数(StartNow)?代码可以放在文档类或电影剪辑上,我无所谓。这似乎是一个相对简单和常见的做法,但我所有的研究都找不到答案。
谢谢!
2个回答

4
如果你的目标是Flash player 11.4,那么可以使用Worker对象来执行这样一个繁重的函数。我没有FP11,最终制作了一个持续超过300秒的过程生成器。我不得不采用基于状态的方法,再加上一个enter frame listener。在我的情况下,整个复杂的生成过程被分成了逻辑块,这些块足够小,在合理的时间内完成,并且有一个跟踪当前生成阶段的变量。所以,当另一个帧调用生成函数时,它从该变量读取上一个已完成的步骤,使用其数据集执行一次额外的步骤,存储新值并退出该帧。这个过程,不是一个纯异步的过程,而是一个伪多任务处理方法,如果你的使SWF卡顿的函数是可分割的,那么这个方法可能适合你。

只是为了节省一些人的时间:Workers 不适用于 Air Mobile。[句号] (http://help.adobe.com/en_US/as3/dev/WS0191790375a6482943a72da3138ec8eec7e-8000.html)。唉。 - Colonize.bat
@Colonize.bat 感谢你的研究! - Vesper
@Colonize.bat 您使用的AIR版本是什么?工作线程在移动设备上已经得到支持一段时间了:http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/system/Worker.html - user45623
@user45623 那条评论是2013年的,当时工作者们还不在移动平台上工作。 - Vesper

2
在Flash中,没有异步运行函数的概念,除非你想使用Workers(就像Vesper所说的那样),否则你必须自己实现。Workers可以给你一个单独的进程。否则,你需要将计算分成几个部分。下面是具体操作:
假设"trace"是一个非常耗费资源的操作。虽然它不是,但这里只是为了举例说明。这个简单的for循环在帧上运行,并导致较低的帧速率,因为它在帧实际渲染之前计算完所有内容。
for(var i:int = 0; i < 1000; i ++)
{
   trace(i); // heavy calculation here
}

因此,您必须将计算分解为几个部分,并使其能够随时间计算。

要做到这一点,您需要创建一个函数,每次只取循环的一部分:

calculatePart(0, 1000, 20);

function calculatePart(startIndex:int, endIndex:int, amountPerRun:int)
{
    for(var i:int = startIndex; (i < startIndex + amountPerRun) || (i < endIndex); i ++)
    {
        trace(i); // heavy calculation here
    }
    if (i < endIndex)
    {
        calculatePart(i, endIndex, amountPerRun);
    }
}

这实际上是与第一段代码中简单的for循环相同的函数,它也输出了1000个跟踪。它已准备好分批运行,但目前还没有异步。我们现在可以很容易地更改函数,使其随时间操作。 我使用setTimeout来实现。您也可以使用ENTER_FRAME事件侦听器或Timer类来实现,但为了方便起见,我在本例中尝试保持清晰。

calculatePart(0, 1000, 20, 100);

function calculatePart(startIndex:int, endIndex:int, amountPerRun:int, timeBeforeNextRun:Number)
{
    for(var i:int = startIndex; (i < startIndex + amountPerRun) && (i < endIndex); i ++)
    {
        trace(i); // heavy calculation here
    }
    if (i < endIndex)
    {
        setTimeout(calculatePart, timeBeforeNextRun, i, endIndex, amountPerRun, timeBeforeNextRun);
    }
}

正如您所见,我添加了一个timeBeforeNextRun参数。如果您运行示例,您会发现需要100毫秒才能输出20个跟踪结果。

如果您将其设置得非常低,则会尝试在很短的时间内进行计算,但是您当然不能仅通过在更短的时间内尝试做更多的事情来获得额外的速度。您必须玩弄时间和数量变量,可以测试哪个实际上提供更好的性能(或者减少延迟)。

 // more time between a run, less calculations per run
 calculatePart(0, 1000, 30, 10);

 // more calculations per run, more time between a run
 calculatePart(0, 1000, 100, 30);

希望这能帮到您。
如果您想使用更智能的时间计算,我发现这个实用程序类非常有用,它测量了计算实际花费的时间,并改变时间本身。链接在此:https://code.google.com/p/imotionproductions/source/browse/#svn/trunk/nl/imotion/utils/asyncprocessor

非常有帮助。我的主要问题是我需要在多个模块之间调用许多繁重的进程,并将每个进程的进度百分比发送到 .fla 文件中,在加载屏幕上显示。例如,从文件中读取 bytearray 可能需要一些时间,并显示进度... - CodeMouse92
顺便问一下,是否有可能反转工作器的逻辑,让它打开一个较小的窗口来显示进度,因为涉及到准备文档类及其自定义类的主实例的重型函数? - CodeMouse92
我已经提出了一个关于工作线程的新问题。然而,由于这是对我的原始问题最完整的答案,我已经接受了它。谢谢!我的新问题在这里:http://stackoverflow.com/questions/13535868/loading-screen-as-worker - CodeMouse92

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接