Асинхронный запуск функции AS3
У меня возникли некоторые проблемы с осмыслением некоторых руководств для этого онлайн, поэтому я спрашиваю здесь. (Использование ActionScript 3, Adobe AIR и Flash Professional CS5.5)
У меня есть очень тяжелая функция в моем классе документов AS3, которую нужно запускать асинхронно, поэтому она не останавливает код самого MovieClip (не спрашивайте меня почему, просто так должно быть).
Итак, проще говоря, как я могу запустить эту функцию класса документа (StartNow) асинхронно? Код может быть помещен в класс документа или в мувиклип, мне все равно, где. Кажется, это относительно простая и распространенная практика, но все мои исследования ничего не выкапывают.
Спасибо!
2 ответа
Во Flash нет такой вещи, как запуск функции асинхронно, вы должны делать это самостоятельно, если вы не хотите использовать Workers (как сказал Веспер). Работники дают вам отдельный процесс. В противном случае вы должны разбить свой расчет на части. Вот как вы это делаете:
Визуализация "следа" является очень тяжелой операцией. Это не так, но только для иллюстрации. Этот простой цикл 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
параметр. Если вы запустите пример, вы увидите, что для вывода 20 трасс требуется 100 миллисекунд.
Если вы установите очень низкое значение, будет предпринята попытка сделать расчет очень быстрым, однако вы не сможете набрать дополнительную скорость, просто пытаясь сделать больше за меньшее время. Вы должны поиграть с переменными времени и количества, вы можете проверить, какая из них на самом деле дает лучшую производительность (или меньшую задержку).
// 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, есть объекты Worker, которым можно назначить такую тяжелую функцию. У меня не было FP11, и в итоге я создал процедурный генератор, который работал в общей сложности более 300 секунд на одну итерацию. Мне пришлось использовать подход, основанный на состоянии, в сочетании со слушателем ввода кадра. В моем случае весь сложный процесс генерации был разбит на логические куски, которые были достаточно малы, чтобы их можно было выполнить за разумный промежуток времени, и имели переменную, отслеживающую текущую фазу генерации. Таким образом, когда другой кадр называется функцией генерации, он считывает последний завершенный шаг из этой переменной, выполняет один дополнительный шаг со своим набором данных, сохраняет новое значение и выходит из кадра. Это, как есть, не чисто асинхронный процесс, а псевдо-многозадачный подход, он может подойти вам, если ваша функция, которая делает вашу SWF-задержку разделяемой.