Что лучше для анонимных слушателей событий? - PullRequest
1 голос
/ 20 июля 2010

Я пытаюсь найти лучший вариант использования анонимных прослушивателей событий, которые на 100% собираются после использования.Я получил эти два примера, но мне интересно, имеет ли это какое-то значение между ними ...

var listener1:Function = function(e:Event):void
{
 resource.removeEventListener(e.type, listener1);
 loadedHandler(resource);
 listener1 = null;
};
resource.addEventListener(ResourceEvent.LOADED, listener1);

или этим ...

resource.addEventListener(ResourceEvent.LOADED, function(e:Event):void
{
 Resource(e.currentTarget).removeEventListener( e.type, arguments["callee"]);
 loadedHandler(resource);

}, false, 0, true);

Или будет лидругое, лучшее решение?Для меня очень важно, чтобы эти слушатели и функции правильно удалялись из памяти, потому что они могут очень часто выполняться в приложении.Я мог бы пойти и использовать Словарь для сопоставления всех слушателей и т. Д., А затем протестировать и удалить их в неанонимных слушателях и т. Д., Но это может быть очень быстрым, потому что могут быть ситуации, когда ресурсы могут загружаться асинхронно одновременнов разных классах приложения.


@ dominic: Вы имеете в виду размещение такой функции в теле метода, верно?Как я писал выше, приложение загружает ресурсы асинхронно, и может случиться так, что ресурс в данный момент загружается, в то время как другой класс откуда-то еще в приложении запрашивает тот же ресурс.Класс управления ресурсами (в котором содержится указанный код) затем подключается к прослушивателям событий, отправляемых ресурсом.Насколько я понимаю, если я использую методы или функции класса, как в вашем примере, в качестве слушателей, они будут повторно использоваться новым запросом, и события для более старого запроса никогда не будут срабатывать.Следовательно анонимные функции хранятся в переменной.Я предполагаю, что они все остаются в памяти, пока их соответствующий запрос не будет выполнен.Но, может быть, я полностью запутал это, и это не так?Я иногда нахожу материал мероприятия очень трудным для понимания.

Ответы [ 5 ]

2 голосов
/ 20 июля 2010

Это не дает прямого ответа на ваш вопрос "vs", но я собираюсь выпустить порт AS3 .NET Reactive Extensions , называемый raix , который решает проблемы, как это :

Observable.fromEvent(resource, ResourceEvent.LOADED)
    .take(1)
    .subscribe(function(e : ResourceEvent) : void
    {
        // just the subscriber code
    });

Использование take означает, что оно будет автоматически отписываться после первого события. Вы также можете вручную подписать ссылку на метод, если вам не нравятся анонимные функции, не беспокоясь об их удалении позже.

Хотя это не так, пожалуйста, дайте мне знать, если этот ответ слишком "спам", и я его удалю.

2 голосов
/ 20 июля 2010

Первый выглядит чище, и вы избегаете использования приведения и поиска в массиве для удаления слушателя. Почему вы используете «анонимные» функции-обработчики? Вы можете использовать это так, это немного чище, и именно так Asdocs предлагает использовать модель событий.

function listener1(e:ResourceEvent):void
{
    resource.removeEventListener(e.type, listener1);
    loadedHandler(resource);
};
resource.addEventListener(ResourceEvent.LOADED, listener1);
1 голос
/ 20 июля 2010

Функция / метод обработчика событий здесь на самом деле не проблема.

Если я понимаю, что вы говорите, так это то, что у вас есть класс ResourceManager, который загружает определенный ресурс по запросу классав вашем приложении.Когда ресурс полностью загружен, ресурс отправляет событие, которое вызовет ваш обработчик событий:

resource.addEventListener(ResourceEvent.LOADED, listener1);

Так что теперь будет вызываться функция или метод listener1.Дело в том, что если в listener1 вы решите удалить прослушиватель событий, теперь дальнейшее завершение загрузки ресурсов вызовет обработчик listener1, потому что менеджер больше не прослушивает его.И если два разных класса в приложении загружают ресурсы одновременно, обработчик listener1 будет вызываться один раз для каждого события ResourceEvent.LOADED.

По моему скромному мнению, вы должны покинуть прослушиватель событий и удалить еготолько после того, как все ресурсы загружены, и используйте диспетчер для управления доступом к загрузке ресурсов, чтобы он был централизованным, и все событие ResourceEvent.LOADED будет обрабатываться функцией / методом listener1.Конечно, если ваше приложение загружает ресурс в течение всего срока его службы, не удаляйте этот слушатель, а удаляйте его только один раз, когда он вам больше не нужен.

Я не уверен на 100%Я поняла, что вы имели в виду, так что я надеюсь, что я не полная тема здесь!Надеюсь, это поможет.

0 голосов
/ 20 июля 2010

Спасибо за подсказку всем! Теперь я выбрал немного более сложное решение, создав простую карту, в которой обработчики нагрузки и ошибок отображаются по идентификатору ресурса. Вот основная идея:

Это заменяет мой оригинальный код:

private var _listeners:Object = {};

public function load(resourceID:String):void
{
    ...

    if (loadedHandler != null || failedHandler != null)
    {
        _listeners[resource.id] = new ListenerVO(loadedHandler, failedHandler);
        if (loadedHandler != null)
        {
            resource.addEventListener(ResourceEvent.LOADED, onResourceProcessed);
        }
        if (failedHandler != null)
        {
            resource.addEventListener(ResourceEvent.FAILED, onResourceProcessed);
        }
    }

    ...
}

Вот новый обработчик событий:

private function onResourceProcessed(e:ResourceEvent):void 
{
    var r:Resource = e.resource;
    var handler:Function;
    r.removeEventListener(e.type, onResourceProcessed);

    if (e.type == ResourceEvent.LOADED)
        handler = ListenerVO(_listeners[r.id]).loadedHandler;
    else if (e.type == ResourceEvent.FAILED)
        handler = ListenerVO(_listeners[r.id]).failedHandler;

    if (handler != null)
    {
        _listeners[r.id] = null;
        delete _listeners[r.id];
        handler(r);
    }
}

И небольшой VO уровня пакета, чтобы держать все это строго типизированным ...

class ListenerVO
{
    public var loadedHandler:Function;
    public var failedHandler:Function;

    public function ListenerVO(lh:Function, fh:Function)
    {
        loadedHandler = lh;
        failedHandler = fh;
    }
}

Дайте мне знать, что вы думаете об этой идее!

0 голосов
/ 20 июля 2010

Я не вижу никакого преимущества в использовании анонимных слушателей в этом случае (хотя в некоторых других случаях это может быть чище, но я думаю, что здесь вы ничего не получите).

В любом случае, есть пара вещей, на которые стоит обратить внимание:

1) Ваш второй вариант напрашивается на неприятности.Не используйте слабые ссылки для анонимных функций.Ваш слушатель может быть собран перед отправкой события.(Я бы сказал, не используйте период слабых ссылок, но в большинстве случаев это скорее личный вкус; в данном случае, однако, это не так).

2) Этот подход будет работать до тех пор, покаВы можете быть уверены, что слушатель будет всегда срабатывать и что это единственное событие, которое будет отправлено.Если ваш диспетчер инициирует какое-либо событие, сигнализирующее об ошибке, ваши слушатели не будут удалены.

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

...