Pull to refresh

Comments 42

Кстати, в this функции onGetResult будет уже не экземпляр Example, а просто global.
Не совсем :) там будет не global, а некая обертка объектов текущего *.as файла (именно файла, а не пакета, и не global), она находится чуть ниже в scope-очереди, однако позволяет достучаться вплоть до global.
Да, повидимому так и есть. Я имел ввиду, что будет контекст не текущего родителя (класса, функции), а что-то более глобальное =)
Стоит отметить, что с усложненеим кода в onGetResult, значительно усложнится и поиск багов.
И надо иметь хорошие знания и опыт в цепочке видимости (scope-chain) и постоянно понимать что onGetResult — это вовсе не метод а функциональная кложура (не знаю как перевести closure, но слово «кожура» — кстати, подходит :)
В командной разработке, думаю, лучше не прибегать к таким методам, ато у новичков от постоянных багов сорвет башню.

Ну, в общем-то, не обязательно помещать много кода в onGetResult, думаю правильным решением будет делегирование обработки вспомогательному классу или просто продиспатить ивент.

На практике, даже в очень больших и запутанных бизнес-логикой проектах, подобные решения как раз таки упрощали код и его понимание. Как минимум на предмет отстутствия бесконечных временных приватных переменных классов для сохранения обрабатываемых объектов.
Руки бы отрывал за вложенные функции.
А вы на них смотрите как на именованные замыкания — и полезно, и руки отрывать не надо :))
Класс! Улыбнулся.
Да потомучто нереально их дебажить это раз, и предсказать их поведение — тоже
Ну, может быть ваша ІDE сталкивается с проблемами при отладке, в Flex Builder всё великолепно. А вот для того, чтобы поведение предсказывалось, я и написал данную статью. Надеюсь, хоть чем-то она кому-то поможет.
как ни странно работаю во Flex IDE

Такой не скромный вопрос, вы когда-нибудь работали в команде хотя бы 5+ человек?
Я тим-лид команды флексеров (4 человека) =)
Ранее всегда работал в командах от 3-4 человек. Я понимаю, что вы стандартно клоните, к тому, что такой код тяжело сопровождать новичкам на проектах — это абсурд. В вышеприведённом коде нет особо секретных костылей или дёрти-хаков, он прост как визуально так и семантически.
эхххх флексеры… не буду ничего говорить. вы бы еще хендлеры запихивали как вложенные функции и тогда бы проекты бы после открытия сжирали по 300 метров… все молчу.
Кстати, да, засовываем довольно успешно. Пользуемся слабыми ссылками при добавлении подобных хендлеров, в результате сборщик мусора отлично их подчищает.
Мое ИМХО — Слабые ссылки зло, сборщик мусора нам не подконтролен, если подписался сам же и отпишись. Я так делаю и никому этот путь не навязываю. Спор беспочвенен.
Слабые ссылки при добавлении ивент хендлеров это дополнительный инструмент, который предоставила Адобе. Правильно пользуясь ими, можно сэкономить в коде и не добавлять в стройную архитектуру проекта вынужденое «уничтожение» для некоторых объектов.

Да и ещё раз да, листенеры нужно удалять вручную, причём, желательно, в тех же местах где они были добавлены. Но, бывают ситуации, когда достаточно расчитывать на слабые ссылки. Если желаете могу приподнести простой пример.
Да, было бы неплохо увидеть пример где применение слабых ссылок:
1) реально обоснованно
2) невозможно использовать стандартный метод подписки, отписки.
Safari can’t connect to the server.
Ваш код заставляет мои глаза кровоточить. Если уж перешли на AS3, то тогда забудьте про AS2 и включите strict mode раз и навсегда.
Не очевидно, почему нужно забыть AS2, только потому, что версия 3 счастливое число?
Режим strict mode включён всегда, надеюсь у вас тоже.
Прошу прощения что так сразу накинулся, попробую объяснить.
Возьму пример из начала текста.
Например, теперь можно описать такую функцию:
public class TestClass
{
	var property : Number;

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


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

Кстати вообще для создания таких функций я бы лучше воспользовался статическим методом класса, вместо того, чтобы для каждой новой функции плодить объекты, которые будут висеть в памяти до великого пришествия GC.

Ещё пример:
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;
}


Далеко не сразу я нашёл объявление _tempObject. Когда я в первый раз читал статью, я решил что оно вообще пропущено, и думаю, не я один. Учитывая тему, к которой относится пример, сразу становится неочевидно, к какой области видимости относится данная переменная, что вносит большую путаницу. Просто потому что переменные и константы всегда определяются до описания методов. Хотя тут я скорее всего придираюсь к мелочам.

Надеюсь, вы воспримете это как конструктивную критику, или даже убедите меня в моей неправоте. Ибо споры между уважающими друг друга оппонентами — процесс довольно приятный и познавательный :)
По-поводу TestClass, зачем так конструктор? Он не нужен, в примере использования ничего в класс не передаётся:

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


Да, в первом примере можно использовать статический метод, а можно вообще ничего не использовать — пример фиктивен. Это просто предисловие к основной теме про контексты, не стоит его воспринимать буквально.

По-поводу _tempObject, даже не знаю как прокоментировать, это не то что-бы придирание к мелочам, это какое-то тонкое издевательство, надеюсь вы шутили =).

По поводу _tempObject я пожалуй погорячился, будем считать что я шутил :)

Про конструктор я говорил относительно этой строчки:

TestClass(this).property = value;
Это:

TestClass(this)

операция приведения типов, сдесь она не обязательна, я написал для наглядности.
Не следует путать запись выше с:

new TestClass(this)
Публично признаю себя слепым идиотом, не сумевшим отличить кастинг от создания экземпляра. Хотя осознание того, что это кастинг, делает эту строчку ещё более загадочной =)
Какую логику вы в неё закладываете?
Что-бы подчеркнуть, что this это екземпляр класса TestClass, а не что-либо другое. В противном случае будет ошибка времени исполнения.
Тогда мне кажется лучше использовать this as TestClass, т.к. эти касты вроде отличаются. Пойду погуглю.
Не лучше, оператор as — это так же оператор приведения типа, но тихий. Если приводимый объект, будет другого типа, то оператор вернёт null и эксепшена не будет. В этом основная разница.
Имхо кастинг в данном случае — это уже паранойя, классы должны быть чёрными ящиками, но сами себе-то они могут доверять! В конце концов это вы создаёте код, и совершенно сознательно пишете данный метод в этом классе. Надо больше в себя верить! :)
Несомненно! Но, так как речь идёт о сохраняемом контексте функций, то данная запись подчёркивает что this(контекст) будет именно таким как и ожидается. В AS2 например, этот же код выполнился бы с эксепшеном, так как this не был бы экземпляром класса TestClass, но того класса, в котором функция бы вызывалась.

Это и есть суть примера, который не стоит принимать как пример для написания кода, только для понимания.
/*
В as2 эта строчка бы выкинула эксепшен, так как метод исполнился бы не в контексте нашего класса, а в том контексте, откуда он был вызван.
*/

Один коммент мог заменить всю нашу беседу :)
Надеюсь, беседа будем полезна как вам, так и тем, кто возможно её прочитает.
Интересные у вас там ребята. Больше мне сказать нечего.
ого, в AS2 есть exception-ы на null object reference-ы:) почему все остальные флешеры этого не знали?:)
ОК, вы правы, эксепшенов до 9 версии флеш плеера, по-моему, небыло. Но, даже не учитывая это, суть моих мыслей надеюсь вам понятна.
Каково еще применение вложенных функций кроме описанного?
Про хендлеры было упоминание выше, я согласен, что полагаться на сборщик не стоит, да и дебажить такие конструкции не слишком удобно.
Кроме того, лично для меня польза того, что обработчик находится в вызывающим асинхронный запрос методе (а по сути в одной области видимости) не совсем очевида. Буду рад если объясните.
Предпочитаю не полагаться на сборщик, а контролировать его посекундно. Для этого мы имеем неплохой инструмент от Адоби, называется Flex Builder Profiler. В нём можно видеть, сколько объектов или функций не уничтожилось, сколько памяти израсходовано. Зачем гадать? Можно же проверить! =)

В чём неудобство отладки таких конструкций? Брейкпоинты в них обрабатываются Flex Builder-ом, стек трейс и состояние памяти показается. Где неудобства?

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

Есть ещё несколько вариантов использования вложеных функций, например передавая их в методы массивов forEach(), filter() — им будут доступны все переменные родительской функции и это можно использовать для поэлементной обработки.
Судя по опыту, в отношении GC — не следует так сильно полагаться. Так в профайлере (debug-версия плеера) и продакшн-версии (обычный плеер) — могут быть совершенно различные картины.
Хм, я про это не знал. Но надеюсь, что это было давно и уже не актуально. Версии плееров постоянно обновляются, не думаю, что Адоби оставила бы таку дыру в оптимизации приложений под её плеер.
Sign up to leave a comment.

Articles