Skip to Content

Функции в Action Script

Я люблю использовать анонимные функции, передавать функции по ссылке, объявлять функции прямо в теле другой функции и т.п. Это удобно и практично, но с этими механизмами могут возникнуть некоторые проблемы. Начиная с версии 9 Flash Player сохраняет в this функции её родителя. Звучит просто, но все ли понимают, что это значит и как тяжело было раньше без этого?

Например, теперь можно описать такую функцию:

 

public class TestClass
{
 var property : Number;

 function updateValue(value : Number) : void
 {
  TestClass(this).property = value;
 }
}

и передавать её куда угодно:

 

var func : Function = new TestClass().updateValue;
func(555);

и быть уверенным, где-бы её не вызвали в this будет экземпляр класса TestClass. Но я не об этом, есть более любопытные действия, которые можно производить над функциями в Action script, их мы их рассмотрим.

Асинхронные вызов

Скорее всего вы сталкивались с задачей вызова удаленного метода на сервере и обработки результата этого вызова. Допустим у нас есть класс сервиса ServerService, который принимает в конструктор ссылку на функцию, которая должна обработать ответ и мы выполняем типичную задачу обновления свойства исходного объекта:

 

class Example
{
 function updateItem(item : SomeObject) : void
 {
  _tempObject = item;
  new ServerService(onGetResult).getResult(item.startValue);
 }

 function onGetResult(result : Object) : void
 {
  _tempObject.endValue = result;
 }

 private var _tempObject : SomeObject;
}

Всё написано верно, но зачем так сложно? Давайте упростим подобную ерунду, «умным» кодом:

 

function updateItem(item : SomeObject) : void
{
 new ServerService(onGetResult).getResult(item.startValue);

 function onGetResult(result : Object) : void
 {
  item.endValue = result;
 }
}

В данном случае функция onGetResult имеет доступ ко всем переменным функции updateItem и к её аргументу item в частности. Такой прием во многих случаях может сократить объем кода и убрать негативный оттенок асинхронности. Кстати, в this функции onGetResult будет уже не экземпляр Example, а просто global.
 

Множественные асинхронные вызовы

Ещё интереснее ситуации когда нужно сделать несколько асинхронных запросов в цикле, а затем обработать каждый ответ соответственно, например:

 

function updateItems(items : ArrayCollection) : void
{
 for each (var item : SomeObject in items)
 {
  new ServerService(onGetResult).getResult(item.startValue);
 }

 function onGetResult(result : Object) : void
 {
  item.endValue = result;
 }
}

Данным кодом мы не достигнем желаемого результата. В тот момент когда сервер вернёт нам ответы, переменная item будет ссылаться на последний элемент коллекции items и все данные присвоятся только ему, слишком много чести! В таких ситуациях не помогает ни сохраняемый контекст функции ни область видимости переменных родителя, тут нужно что-то другое.

Зачастую можно воспользоваться так называемым Loader-ом:

 

function updateItems(items : ArrayCollection) : void
{
 for each (var item : SomeObject in items)
 {
  new ValueLoader(item);
 }
}

class ValueLoader
{
 public function ValueLoader(item : SomeObject)
 {
  new ServerService(onGetResult).getResult(item.startValue);

  function onGetResult(result : Object) : void
  {
  item.endValue = result;
  }
 }
}

так как контекста функции недостаточно что-бы сохранить item для обновления его после ответа сервера, мы создаем над функцией обёртку — класс, которые способен запомнить в контексте всё что нужно. Так как конструктор класса всё та же функция, аргумент item без проблем будет доступен в функции onGetResult.

Стандартизированый объект ContextFunction

В конце концов, если вы нежелаете плодить массу всевозможных Loader-ов, можно ввести универсальный тип — паттерн для многократного использования:

class ContextFunction
{
 public function ContextFunction(targetFunction : Function, ... args)
 {
  _contextArgumnets = args;
  _targetFunction = targetFunction;
 }

 public function func(... args) : void
 {
  var targetArguments : Array = 
  args.concat(_contextArgumnets);
  _targetFunction.apply(this, targetArguments);
 }

 private var _contextArgumnets : Array;

 private var _targetFunction : Function;
}

Суть решения в том, что экземпляр ContextFunction определяется ссылкой на функцию с конкретной логикой и набором неопределённых аргументов, которые получит функция, когда её кто-то вызовет. Так же, к этим аргументам добавятся ещё что-то, по желанию вызывающей сущности. Рассмотрим пример для прояснения:

 

function updateItems(items : ArrayCollection) : void
{
 for each (var item : SomeObject in items)
 {
  new ServerService(new ContextFunction(onGetResult, item).func).
  getResult(item.startValue);
 }
}

function onGetResult(result : Object, item : SomeObject) : void
{
 item.endValue = result;
}

Это по-сути то же решение, что и с Loader-ом, только более универсальное. Экземпляр ContextFunction сохраняет onGetResult, которая получит ответ от сервера, а также ссылку на item для которого запрашивалось серверное значение. То-есть, мы, отказываясь от контекста функции вообще, используем экземпляр вспомагательного класса, для сохранения нужных значений.

В заключение, могу вас уверить, что все эти трюки используются мной на практике очень часто и эффективно. Это не высосанные из пальца проблемы.
 

Комментарии

9SSHaV dnjvatbqxhyi,

9SSHaV dnjvatbqxhyi, [url=http://bpsvwgdhtvqk.com/]bpsvwgdhtvqk[/url], [link=http://krqivmjultqg.com/]krqivmjultqg[/link], http://tejprfjicwry.com/

MdIGBb nbeseufkrnyk,

MdIGBb nbeseufkrnyk, [url=http://plhlgcumgxdt.com/]plhlgcumgxdt[/url], [link=http://qikmtxcdvexk.com/]qikmtxcdvexk[/link], http://outmtzxolqkv.com/

7vD35B wtexaavslksr,

7vD35B wtexaavslksr, [url=http://cvlhviizrjht.com/]cvlhviizrjht[/url], [link=http://gemqkhqnwdlh.com/]gemqkhqnwdlh[/link], http://sigmhwpgnjig.com/

fTR9G7 xiorzfbwtyro,

fTR9G7 xiorzfbwtyro, [url=http://uikufbpvghng.com/]uikufbpvghng[/url], [link=http://dgpclvmppryq.com/]dgpclvmppryq[/link], http://dmdfvygfspks.com/

ytEYHj ymwhdudlljnc,

ytEYHj ymwhdudlljnc, [url=http://zfqckmawgtne.com/]zfqckmawgtne[/url], [link=http://vfuzectrlsud.com/]vfuzectrlsud[/link], http://jvkzpqyiwtgn.com/

PqU2UA frisnsfcsuir,

PqU2UA frisnsfcsuir, [url=http://odkreiznmmnk.com/]odkreiznmmnk[/url], [link=http://hvvrvtlcofpb.com/]hvvrvtlcofpb[/link], http://dzggdtjixmuf.com/

Настройки просмотра комментариев

Выберите нужный метод показа комментариев и нажмите "Сохранить установки".

Отправить комментарий