Асинхронное выполнение функции AS3


У меня возникли некоторые проблемы с пониманием некоторых учебных пособий для этого онлайн, поэтому я спрашиваю здесь. (С помощью ActionScript 3, Adobe AIR и Flash Professional CS5. 5)

У меня есть очень тяжелая функция в моем классе документов AS3, которую мне нужно запускать асинхронно, поэтому она не останавливает код на самом MovieClip (не спрашивайте меня, почему, это просто должно быть так.)

Итак, проще говоря, как я могу запустить эту функцию класса документа (StartNow) асинхронно? Код может быть помещается в класс document или на movieclip, мне все равно где. Это кажется относительно простой и распространенной практикой, но все мои исследования ничего не дают.

Спасибо!

2 4

2 ответа:

Во Flash нет такой вещи, как запуск функции асинхронно, вы должны сделать это сами, если вы не хотите использовать рабочих (как сказал Веспер). Рабочие дают вам отдельный процесс. В противном случае вам придется разбить свой расчет на части. Вот как вы это делаете:

Визуализация "следа" - очень тяжелая операция. Это не так, но просто для иллюстрации. Этот простой цикл 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);

Надеюсь, это поможет.

Если вы хотите использовать более умный расчет времени, я нашел Этот полезный класс очень полезным, который измеряет, сколько времени на самом деле занял расчет, и изменяет само время.

Если ваша цель-Flash player 11.4, есть рабочие объекты, которым можно назначить такую тяжелую функцию. У меня не было FP11, и в конечном итоге я сделал процедурный генератор, который длился более 300 секунд на итерацию в общей сложности. Мне пришлось использовать подход, основанный на состоянии, в паре с прослушивателем входного кадра. В моем c ase весь сложный процесс генерации был разбит на логические блоки, которые были достаточно малы, чтобы быть завершенными в течение разумного промежутка времени, и имели переменную, отслеживающую текущий фаза генерации. Таким образом, когда другой кадр вызывал функцию генерации, он считывал последний завершенный шаг из этой переменной, выполнял один дополнительный шаг со своим набором данных, сохранял новое значение и выходил для кадра. Это, как есть, не чистый асинхронный процесс, а псевдо-многозадачный подход, это может подойти вам, если ваша функция, которая делает вашу SWF-задержку расщепляемой.