处理异步控制结构(Fluent Interface?)

发布于 2024-07-23 06:37:22 字数 977 浏览 9 评论 0原文

我们的 Flex 应用程序的初始化代码正在执行一系列异步调用,以检查用户凭据、加载外部数据、连接到 JMS 主题等。根据应用程序运行的上下文,其中一些调用不会执行或执行不同的参数。

由于所有这些调用都是异步发生的,因此控制它们的代码很难阅读、理解、维护和测试。 对于每个调用,我们需要有一些回调机制,在其中我们决定接下来要执行的调用。

我想知道是否有人尝试过将这些调用包装在可执行单元中,并使用流畅的接口(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:我们在 Spring ActionScript 项目中创建了一个实验性任务 API,用于提供对异步进程的控制。 我们很乐意收到反馈。 http://www.springactionscript.org/docs/reference/html/ the_operation_api.html#tasks

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

幽梦紫曦~ 2024-07-30 06:37:22

我做了类似的事情,专门用于应用程序的初始化。 然而,我在编写它时考虑了 MXML 的使用,因为我们使用 Flex 开发了大部分 Flash 应用程序。

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

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

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

使用 IMXMLObject 等接口,只需将其放入应用程序中就可以很好地工作,嘿,很快,这就是您的初始化代码。 当然,这不必用于初始化,它可以应用于任何地方。

显着的优点:

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

显着缺点:

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

I've done something similar, specifically for the initialization of applications. However, I wrote it with MXML usage in mind since we develop most of our flash applications using Flex.

The syntax looks just like declaring an array (I'm just making up the tags, but you get the idea):

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

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

Using interfaces such as IMXMLObject it works quite well to just slap this into an application and hey presto, there's your initialization code. Of course, this doesn't have to be for initialization, it could apply anywhere.

Notable pros:

  • Order of execution is intuitive, and easy to change (just move a tag up or down)
  • Steps in the list doesn't really care about other steps
  • Data can be passed between steps by using binding syntax, promotes dependancy injection
  • Properly encapsulated single-task steps can very easily be re-used

Notable cons:

  • MXML == angle bracket tax
  • Using bindings for passing data could lead to unexpected results if triggered multiple times
  • Care should be taken that steps adhere to the Single Responsibility Principle, otherwise it can easily become much too complex
小ぇ时光︴ 2024-07-30 06:37:22

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

直接的方法是引入一些单子框架(就像 Haskell 中的)来封装你的异步调用。 但在将程序逻辑转换为 CPS 时,您仍然需要创建多个函数(回调)。 看:
Haskell 中的 CPS。 但语法很丑陋。 良好的语法在Scheme中,但这与Scheme计算模型密切相关:可用于宏处理的宏和库代码。

通过一些语言支持,您可以简化语法:示例是 F# 中的计算表达式,完全异步。 其底层与 Monad 概念密切相关。

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

Definitely you can do this. You can pass action and continuation functions and threat them to be async call and callback. This is called Continuation passing style. This will require to convert you conventional logic to sequence of function calls.

Straightforward way will be to introduce some monadic framework (like in Haskell) that will encapsulate your asynchronous calls. But you still have to create multiple functions (callbacks) while converting your program logic to CPS. See:
CPS in Haskell. But the syntax is ugly. Good syntax is in Scheme, but this is tightly related to Scheme computational model: macros and library code available for macro processing.

With some language support you can simplify the syntax: example is computation expressions in F#, exactly async one. Under the hood is close relative to the Monad concept.

Another interesting idea of high level event driven programming is implemented in Reactive Extensions for .NET (Rx). The idea is pretty simple: events are very simiplar to lists. The difference is that you don't construct them (push based collection), but rather you get next element from them (pull based collection). Invert an interface correspondingly: instead of MoveNext and Current in IEnumerator you will get OnNext, OnDone and OnError in IObservable. An then, combining existing observables you can get something close to code you suggested.

半城柳色半声笛 2024-07-30 06:37:22

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

If it comes to using Flex and having insight in the flow of asynchronous calls I would use the archectural framework Mate. As the Api states: 'A fundamental part of Mate is the EventMap tag which allows you define mappings for the events that your application creates. It is basically a list of IActionList blocks, where each block matches an event type[..]" Now in each EventMap you can have several asynchronous server calls that are logically connected to each other. The whole thing is mxml tag based, so also very easy to read.

萌逼全场 2024-07-30 06:37:22

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

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

这并没有错,但以正确的方式思考会让你找到正确的文献。 例如,不必与内部结构作斗争,以便 .else() 部分知道它配对的是哪个 .if(),只需编写一个完整的解析器并向其发送一个字符串与你的程序。

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

since your functions must be asynchronous, you can't make them block to wait for the next action, so all they do is stash some codes in a structure that will be executed later.

sounds familiar? in short, you're compiling a language and executing a VM.

nothing wrong with that, but thinking in the right terms will let you search for the right literature. for example, instead of fighting with your internal structure so the .else() part knows which .if() it pairs, just write a full parser and send it a string with your program.

also there are lots of examples on writing simple VMs

这个俗人 2024-07-30 06:37:22

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

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

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

我非常有兴趣了解它的进展情况,因为我现在正在 AIR 应用程序中执行此操作,而且我对此感到非常满意。

Much of this is very interesting discussion on this type of programming. It's also the weakest part of our most common languages, and it's very painful to express asynchronous logic within a synchronous language. I believe continuations are the answer here because we can think synchronous and program synchronous, but model asynchronous program control flow easily. Synchronous programming is very well understood and reuse is very easy. Async not at all. But, until the world catches up...alas.

What you're suggesting looks interesting but I've done this type of thing now at least twice, and never been happy with it. I think you're going to have a difficult time to evaluate your if blocks at runtime. The problem I've always had was getting the data from one step to the next in a clean manner. How are you going to write a if statement against values that might not be present until after a step has run.

If I were you I'd consider looking at the State pattern. State pattern models this type of behavior in objects and the transitions can be performed asynchronously. YOu might be able to create a Fluent interface for creating States like you have above.

I'd be very interested in hearing how it goes as I'm doing this exact thing in my AIR app now, and I'm only sorta happy with it.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文