Форум Flasher.ru
Ближайшие курсы в Школе RealTime
Список интенсивных курсов: [см.]  
  
Специальные предложения: [см.]  
  
 
Блоги Правила Справка Пользователи Календарь Сообщения за день
 

Вернуться   Форум Flasher.ru > Flash > Flex

Версия для печати  Отправить по электронной почте    « Предыдущая тема | Следующая тема »  
Опции темы Опции просмотра
 
Создать новую тему Ответ
Старый 10.04.2008, 14:05
WindWalker вне форума Посмотреть профиль Отправить личное сообщение для WindWalker Найти все сообщения от WindWalker
  № 21  
Ответить с цитированием
WindWalker
[+1 18.03.08]

Регистрация: Nov 2006
Сообщений: 223
waitForClick - всего лишь тривиальный пример.
А как тебе такое:
Код:
var connected:bool = false;
var attempts:int=0;
while (!connected && attempts<3) {
   if (sock.connect()) {
       connected = true;        
   } else {
       attempts++;
       sleep(500);
   }
}
Никакого соединения с сервером ещё нет, так что свалить не на кого.

sock.connect() и sleep() в данном случае - синхронные методы.
Попробуй написать вышеприведённый код на классическом AS3, затем сравним.

-------------------------

Другой пример.
В одном проекте мне необходимо было рисовать различные псевдо-3D объекты в аксонометрической проекции. Для отрисовки каждого объекта требуется одна или несколько текстур. Текстуры хранятся во внещних файлах.
Разумеется, загружать текстуру каждый раз, когда он потребовалась - слишком дорогое удовольствие, поэтому я сделал кеш текстур, основной метод которого выглядел так:
Код:
public static function getTexture(sPath:String):BitmapData
При старте приложения загружались все необходимые текстуры (коих тогда было мало), затем объекты в любой момент могли взять нужные текстуры.

Но после уточнения ТЗ оказалось, что в реальной работе текстур может быть тысячи, а то и десятки тысяч. Все их загружать в память просто не реально.
Поэтому надо использовать ленивую загрузку - текстура загружается только при первом обращении к ней.

Но в таком случае я не могу сразу вернуть BitmapData! Ведь возможно такой текстуры в кеше ещё нет, следовательно она будет загружаться, следовательно потребуется какое-то время.
Пришлось добавлять callback'и. Но мало того - пришлось полностью переделывать отрисовку объектов. Если раньше это был один метод (у разных типов объектов - свой), то теперь мне пришлось его разбивать на части, чтобы гарантировать, что текстура точно загружена.
Если бы я мог сделать getTexture синхронным, то таких значительных переделок не потребовалось бы.


Последний раз редактировалось WindWalker; 10.04.2008 в 14:45.
Старый 10.04.2008, 14:25
etc вне форума Посмотреть профиль Найти все сообщения от etc
  № 22  
Ответить с цитированием
etc
Et cetera
 
Аватар для etc

Регистрация: Sep 2002
Сообщений: 30,787
Ну connect в AS3 не синхронный, начнем с этого.

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

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


Последний раз редактировалось etc; 10.04.2008 в 14:41.
Старый 10.04.2008, 14:37
FlexOkeks вне форума Посмотреть профиль Отправить личное сообщение для FlexOkeks Найти все сообщения от FlexOkeks
  № 23  
Ответить с цитированием
FlexOkeks
 
Аватар для FlexOkeks

Регистрация: Sep 2007
Адрес: Путенбург
Сообщений: 147
Из много букв, отбросив лишнее, выделил такую суть:
Цитата:
Сообщение от WindWalker
Возникают проблемы:

1. Код разрастается и становится не таким очевидным. Например, другой разработчик, посмотрев на такой код, может не сразу понять, в каком порядке вызываются действия.

2. Вместо локальных переменных приходиться использовать приватные поля для тех данных, которые должны быть общими для разных функций.

3. Некоторые обработчики одноразовые. После срабатывания они должны быть отключены (например, обработчик hand-shake должен сработать один раз. Дальнейший сетевой обмен никак не должен его задействовать).

4. Необходимо заранее задумываться о том, какие действия у нас "мгновенные", а какие "долгоиграющие", чтобы правильно разбивать функции на части.

Попробуем всё-таки скомпоновать всё в одну функцию, чтобы частично решить проблемы 1, 2 и 3.

Мы временно устанавливаем обработчики событий, после срабатывания отключаем предыдущий обработчик и прописываем следующий (в более сложном случае - ещё и инициируем действие, например, начинаем загрузку файла или отправляем запрос серверу).
Сомнительное решение, проблему 1 например мы не только не решили, но и усугубили, она у нас оказалась главным недостатком:
Цитата:
Сообщение от WindWalker
Достоинства:
1. Действия выполняются строго по порядку.
2. В целом, имеем одну функцию, в которой чётко виден порядок действий.
3. Вложенные функции имеют доступ к локальным переменном основной функции.

Недостатки:
1. Очень много "мусорного" кода, который приходиться набирать и который затрудняет чтение.

Решение: изменить компилятор таким образом,
Слишком дорогой способ решать банальные проблемы, да и проблема возможно просто в привычке, если привык работать с несколькими потоками, трудно привыкнуть к тому, что нельзя создать отдельный поток. У использования потоков есть свои преимущества, но в AS их нельзя использовать непосредственно, а эмуляция оных имхо в данном примере приносит больше сложностей, чем пользы, то есть это интересно может быть чисто теоретически, но практически пока не понятно зачем это.
__________________
<!-- КРЭКС ПЭКС ФЛЭКС -->

Старый 10.04.2008, 14:40
WindWalker вне форума Посмотреть профиль Отправить личное сообщение для WindWalker Найти все сообщения от WindWalker
  № 24  
Ответить с цитированием
WindWalker
[+1 18.03.08]

Регистрация: Nov 2006
Сообщений: 223
Именно!
Приведённый код - пример того, как выглядел бы код, если бы connect был синхронным.

Напиши эквивалент этого кода с помощью асинхронного connect.
И мы вместе почувствуем разницу.

Старый 10.04.2008, 14:47
FlexOkeks вне форума Посмотреть профиль Отправить личное сообщение для FlexOkeks Найти все сообщения от FlexOkeks
  № 25  
Ответить с цитированием
FlexOkeks
 
Аватар для FlexOkeks

Регистрация: Sep 2007
Адрес: Путенбург
Сообщений: 147
Цитата:
Сообщение от WindWalker
Попробуй написать вышеприведённый код на классическом AS3, затем сравним.
А это точно, дело привычки! А попробуйте (допишите сами ) на классическом (допишите сами) и посмотрим кто круче, типа того.
__________________
<!-- КРЭКС ПЭКС ФЛЭКС -->

Старый 10.04.2008, 14:50
etc вне форума Посмотреть профиль Найти все сообщения от etc
  № 26  
Ответить с цитированием
etc
Et cetera
 
Аватар для etc

Регистрация: Sep 2002
Сообщений: 30,787
Цитата:
Сообщение от WindWalker
Именно!
Приведённый код - пример того, как выглядел бы код, если бы connect был синхронным.

Напиши эквивалент этого кода с помощью асинхронного connect.
И мы вместе почувствуем разницу.
Я разницу не почуствую, мне синхронность не нужна. Набросал:

Код:
…
    socket.addEventListener(IOErrorEvent.IO_Error, this.handler_ioError);
…
private var _attempts:uint = 0;

private var _timeoutID:uint;

private function connect():void {
    this._attempts++;
    try {
        socket.connect(…);
    } catch (error:Error) {
        this.attempt();
    }
}

private function attempt():void {
    if (this._attempts > 2) {
        clearTimeout(this._timeoutID);
        // bla-bla, показываем ошибку
        
    } else this._timeoutID = setTimeout(this.connect, 500);
}

private function handler_ioError(event:IOErrorEvent):void {
    this.attempt();
}
Подлиннее, конечно (правильность работы не проверял, правда), но никаких потоков, sleep и прочей ботвы вообще не надо. Но это общая идеология работы AS3. AS3 != Java, хоть убей.

Старый 10.04.2008, 15:06
WindWalker вне форума Посмотреть профиль Отправить личное сообщение для WindWalker Найти все сообщения от WindWalker
  № 27  
Ответить с цитированием
WindWalker
[+1 18.03.08]

Регистрация: Nov 2006
Сообщений: 223
Итак, во-первых - длиннее.
Во-вторых, цикл уже не так очевиден.
В-третьих - порядок действий уже не так очевиден, появляется псевдорекурсия: connect может вызвать attempt, attempt косвенно вызывает connect.

B это всего для двух "долгоиграющих" действий: connect и таймаут.

Теперь маленькое добавление: если соединение не удалось, то показать диалоговое окно с надписью: "Connection failed" и кнопкой OK.
Делать следующую попытку только после того, как пользователь нажмёт OK.

Как меняется код на выдуманном языке:
Код:
var connected:bool = false;
var attempts:int=0;
while (!connected && attempts<3) {
   if (sock.connect()) {
       connected = true;        
   } else {
       showMessage("Error", "Connection failed", [OK]);
       attempts++;
       sleep(500);
   }
}
Ваш ход?

-------------------

Цитата:
Сообщение от __etc
Подход к текстурам неверный, поверхность должна получить адрес текстуры и все, она начнет грузить текстуру или не начнет, пусть сама решает.
А если эта текстура уже загружена?
А если другая поверхность начала загружать эту текстуру, но ещё пока не загрузила?


Последний раз редактировалось WindWalker; 10.04.2008 в 15:19.
Старый 10.04.2008, 15:15
etc вне форума Посмотреть профиль Найти все сообщения от etc
  № 28  
Ответить с цитированием
etc
Et cetera
 
Аватар для etc

Регистрация: Sep 2002
Сообщений: 30,787
Код:
…
    socket.addEventListener(IOErrorEvent.IO_Error, this.handler_ioError);
…
private var _attempts:uint = 0;

private var _timeoutID:uint;

private function connect():void {
    this._attempts++;
    try {
        socket.connect(…);
    } catch (error:Error) {
        this.attempt();
    }
}

private function attempt():void {
    if (this._attempts > 2) {
        // bla-bla, показываем ошибку
        
    } else {
         this.showMessage("Error", "Connection failed", Message.OK);
    }
}

private function handler_ioError(event:IOErrorEvent):void {
    this.attempt();
}

private function handler_okClick(event:Event):void {
    this.hideMessage();
    this.connect();
}
Как-то так. Рекурсии не будет. В чем проблема?

Старый 10.04.2008, 15:30
WindWalker вне форума Посмотреть профиль Отправить личное сообщение для WindWalker Найти все сообщения от WindWalker
  № 29  
Ответить с цитированием
WindWalker
[+1 18.03.08]

Регистрация: Nov 2006
Сообщений: 223
Итого: +1 функция (новый обработчик).

addListener в одном месте, действие, которое может инициировать событие - в другом, обработчик события - в третьем, и после этого ещё и повторный вызов connect.

А теперь дальше.
QA посмотрели наше приложение и сказали: что-то слишком часто сообщение появляется. Надо сделать так, чтобы сперва делалось три попытки (молча), а если они не удались, то тогда уже показывать сообщение. Между попытками пауза 500 мс.
Сообщение должно теперь содержать YES и NO. Если отвечает YES, то снова делать три попытки.

Код:
var connected:bool = false;
var attempts:int=0;
do {
   while (!connected && attempts<3) {
      if (sock.connect()) {
          connected = true;        
      } else {          
          attempts++;
          sleep(500);
      }
   }

   if (!connected) {
      var answer = showMessage("Error", "Connection failed", [BTN_YES, BTN_NO]);
   }   
} while (!connected && answer == BTN_YES);
Уже чуть-чуть подлинее. Но порядок действий по-прежнему виден.

Ваш ход?

Старый 10.04.2008, 15:40
etc вне форума Посмотреть профиль Найти все сообщения от etc
  № 30  
Ответить с цитированием
etc
Et cetera
 
Аватар для etc

Регистрация: Sep 2002
Сообщений: 30,787
Я не играю с вами в шахматы, потому как мой ход очевиден и смысла в продолжении нет. Если вы ради сомнительного удобства собираетесь ваять конвееры и псевдомногопоточность — вперед. Но это AS way, и это не Java, в очередной раз говорю.
Вам всего навсего нужен sleep, а многопоточность тут особо и не нужна.
Чего вы хотите примерами кода доказать — я не знаю. Я вам докажу, что можно без многопоточности, пусть и длиннее, но никаких проблем в понимании логики лично я не вижу. Если вы видите, то AS — не ваше.


Последний раз редактировалось etc; 10.04.2008 в 15:42.
Создать новую тему Ответ Часовой пояс GMT +4, время: 07:28.
Быстрый переход
  « Предыдущая тема | Следующая тема »  

Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.


 


Часовой пояс GMT +4, время: 07:28.


Copyright © 1999-2008 Flasher.ru. All rights reserved.
Работает на vBulletin®. Copyright ©2000 - 2026, Jelsoft Enterprises Ltd. Перевод: zCarot
Администрация сайта не несёт ответственности за любую предоставленную посетителями информацию. Подробнее см. Правила.