Работа с асинхронными структурами управления (Fluent Interface?) - PullRequest
4 голосов
/ 03 июня 2009

Код инициализации нашего приложения Flex выполняет серию асинхронных вызовов для проверки учетных данных пользователя, загрузки внешних данных, подключения к теме JMS и т. Д. В зависимости от контекста, в котором выполняется приложение, некоторые из этих вызовов не выполняются или выполнены с другими параметрами.

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

Мне было интересно, экспериментировал ли кто-нибудь с упаковкой этих вызовов в исполняемые модули и наличием Fluent Interface (FI), который мог бы соединять и контролировать их.

С моей головы код может выглядеть примерно так:

var asyncChain:AsyncChain = execute(LoadSystemSettings)
.execute(LoadAppContext)
.if(IsAutologin)
  .execute(AutoLogin)
.else()
  .execute(ShowLoginScreen)
.etc;
asyncChain.execute();

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

Это может быть интересной идеей для сред, работающих в однопоточной модели, таких как Flash Player, Silverlight, JavaFX ?, ...

Прежде чем погрузиться в код, чтобы попробовать, я надеялся получить какую-то обратную связь.


Обновление 19/03/2010 : Мы создали экспериментальный Task API в проекте Spring ActionScript, который обеспечивает контроль над асинхронными процессами. Мы будем рады получить обратную связь. http://www.springactionscript.org/docs/reference/html/the_operation_api.html#tasks

Ответы [ 5 ]

2 голосов
/ 26 февраля 2010

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

Синтаксис выглядит так же, как объявление массива (я просто составляю теги, но вы поняли):

<Initialize>
    <DisplayPreloader />
    <LoadConfiguration id="configurationLoader" source="foo.xml" />
    <ParseConfiguration source="{configurationLoader.result}" />

    <!-- ... --->
</Initialize>

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

Известные плюсы:

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

Заметные минусы:

1 голос
/ 19 марта 2010

Если речь идет об использовании Flex и понимании потока асинхронных вызовов, я бы использовал структуру архитектуры Mate . Как утверждает Api: «Фундаментальной частью Mate является тег EventMap, который позволяет вам определять сопоставления для событий, которые создает ваше приложение. В основном это список блоков IActionList, где каждый блок соответствует типу события [..] "Теперь в каждом EventMap вы можете иметь несколько асинхронных серверных вызовов, которые логически связаны друг с другом. Все это основано на теге mxml, поэтому очень легко читается.

1 голос
/ 19 февраля 2010

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

Простым способом будет введение некоторой монадической структуры (, как в Haskell ), которая будет инкапсулировать ваши асинхронные вызовы. Но вам все равно придется создавать несколько функций (обратных вызовов) при преобразовании логики вашей программы в CPS. Увидеть: CPS в Хаскеле . Но синтаксис уродлив. Хороший синтаксис в Scheme, но он тесно связан с вычислительной моделью Scheme: макросы и библиотечный код доступны для обработки макросов.

С помощью некоторой языковой поддержки вы можете упростить синтаксис: например, вычислительные выражения в F #, в точности async one . Под капотом находится тесная связь с концепцией Monad.

Еще одна интересная идея высокоуровневого программирования на основе событий реализована в Reactive Extensions for .NET (Rx) . Идея довольно проста: события очень похожи на списки. Разница в том, что вы их не создаете (коллекция на основе push), а скорее получаете следующий элемент из них (коллекция на основе pull). Соответственно, инвертируйте интерфейс: вместо MoveNext и Current в IEnumerator вы получите OnNext, OnDone и OnError в IObservable. Затем, комбинируя существующие наблюдаемые, вы можете получить что-то близкое к предложенному вами коду.

0 голосов
/ 26 февраля 2010

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

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

Если бы я был на вашем месте, я бы рассмотрел модель состояния. Шаблон состояния моделирует этот тип поведения в объектах, и переходы могут выполняться асинхронно. Возможно, вам удастся создать интерфейс Fluent для создания состояний, подобных описанным выше.

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

0 голосов
/ 03 июня 2009

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

звучит знакомо? короче говоря, вы компилируете язык и запускаете виртуальную машину.

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

также есть много примеров написания простых виртуальных машин

...