4

The initialization code of our Flex application is doing a series of asynchronous calls to check user credentials, load external data, connecting to a JMS topic, etc. Depending on the context the application runs in, some of these calls are not executed or executed with different parameters.

Since all of these calls happen asynchronously, the code controlling them is hard to read, understand, maintain and test. For each call, we need to have some callback mechanism in which we decide what call to execute next.

I was wondering if anyone had experimented with wrapping these calls in executable units and having a Fluent Interface (FI) that would connect and control them.

From the top of my head, the code might look something like:

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

The AsyncChain would be an execution tree, build with the FI (and we could of course also build one without a FI).

This might be an interesting idea for environments that run in a single threaded model like the Flash Player, Silverlight, JavaFX?, ...

Before I dive into the code to try things out, I was hoping to get some feedback.


Update 19/03/2010: We have created an experimental Task API in the Spring ActionScript project that provides control over async processes. We'd be happy to get feedback. http://www.springactionscript.org/docs/reference/html/the_operation_api.html#tasks

4

5 回答 5

2

我做过类似的事情,专门用于应用程序的初始化。但是,由于我们使用 Flex 开发大多数 Flash 应用程序,因此我在编写它时考虑了 MXML 的使用。

语法看起来就像声明一个数组(我只是在编造标签,但你明白了):

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

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

使用诸如 IMXMLObject 之类的接口,只需将其放入应用程序中就可以很好地工作,嘿,这就是您的初始化代码。当然,这不一定是为了初始化,它可以应用于任何地方。

值得注意的优点:

  • 执行顺序直观,易于更改(只需向上或向下移动标签)
  • 列表中的步骤并不真正关心其他步骤
  • 数据可以通过使用绑定语法在步骤之间传递,促进依赖注入
  • 正确封装的单任务步骤可以很容易地重复使用

显着的缺点:

  • MXML ==尖括号税
  • 如果多次触发,使用绑定传递数据可能会导致意外结果
  • 应注意步骤遵循单一职责原则,否则很容易变得过于复杂
于 2010-02-25T23:03:10.140 回答
1

你绝对可以做到这一点。您可以传递操作和延续函数,并威胁它们是异步调用和回调。这称为继续传递风格。这将需要将您的常规逻辑转换为函数调用序列。

直截了当的方法是引入一些封装异步调用的单子框架(如在 Haskell 中)。但是在将程序逻辑转换为 CPS 时,您仍然必须创建多个函数(回调)。请参阅: Haskell 中的 CPS。但是语法很丑。Scheme 中有很好的语法,但这与 Scheme 计算模型密切相关:宏和可用于宏处理的库代码。

借助一些语言支持,您可以简化语法:例如 F# 中的计算表达式,完全是async one。引擎盖下与 Monad 概念密切相关。

高级事件驱动编程的另一个有趣想法是在Reactive Extensions for .NET (Rx)中实现的。这个想法很简单:事件与列表非常相似。不同之处在于您不构造它们(基于推送的集合),而是从它们中获取下一个元素(基于拉取的集合)。相应地反转接口:而不是 IEnumerator 中的 MoveNext 和 Current,您将在 IObservable 中获得 OnNext、OnDone 和 OnError。然后,结合现有的 observables,您可以获得接近您建议的代码的东西。

于 2010-02-19T09:22:01.733 回答
1

如果涉及到使用 Flex 并深入了解异步调用的流程,我会使用架构框架Mate。正如 Api 所述:“Mate 的一个基本部分是 EventMap 标签,它允许您为应用程序创建的事件定义映射。它基本上是一个 IActionList 块的列表,其中每个块都匹配一个事件类型[..]”现在在每个 EventMap 中,您可以有几个逻辑上相互连接的异步服务器调用。整个事情都是基于 mxml 标记的,所以也是很容易阅读。

于 2010-03-19T07:44:50.533 回答
0

由于您的函数必须是异步的,因此您不能让它们阻塞以等待下一个动作,因此它们所做的只是将一些代码存储在稍后将执行的结构中。

听起来很熟悉?简而言之,您正在编译一种语言并执行一个虚拟机。

这没有错,但是用正确的术语思考会让你搜索到正确的文献。例如,与其与您的内部结构争吵以便该.else()部分知道.if()它配对的是哪个,只需编写一个完整的解析器并将其与您的程序一起发送一个字符串。

还有很多关于编写简单虚拟机的例子

于 2009-06-03T17:21:19.140 回答
0

其中大部分是关于此类编程的非常有趣的讨论。它也是我们最常用语言中最薄弱的部分,在同步语言中表达异步逻辑非常痛苦。我相信延续是这里的答案,因为我们可以认为同步和程序同步,但很容易建模异步程序控制流。同步编程很容易理解,重用也很容易。一点也不异步。但是,直到世界赶上来……唉。

你的建议看起来很有趣,但我现在至少做过两次这种事情,而且从来都不满意。我认为您将很难在运行时评估您的 if 块。我一直遇到的问题是以干净的方式从一个步骤到另一个步骤获取数据。您将如何针对在一个步骤运行后可能不存在的值编写 if 语句。

如果我是你,我会考虑查看状态模式。状态模式对对象中的此类行为进行建模,并且可以异步执行转换。你也许可以像上面那样创建一个 Fluent 接口来创建状态。

我很想听听它是如何进行的,因为我现在正在我的 AIR 应用程序中做这个确切的事情,我只是对此感到满意。

于 2010-02-25T22:31:34.790 回答