首页 > 解决方案 > scxml 事件中的循环调用

问题描述

我有一个带有“调用”元素的 scxml 事件。当事件被调用时,这个调用元素会更新数据模型元素。我怎样才能使这种情况定期发生?例如,是否可以每秒定期调用此调用?或者也许每秒都过渡到事件?

后者的问题是,如果我在调用的 finalize 部分放置一个转换,调用它自己,它似乎不会多次调用调用部分。

标签: recursionscxmlapache-commons-scxml

解决方案


我首先想提供一些关于<invoke>. <invoke>被放置为一个孩子<state>。它在进入状态时启动子状态机会话,并在退出状态时停止会话。此外,如果子会话进入<final>状态,则done.invoke.invokeid在父会话上调度事件。您可以done.invoke.invokeid在父状态的转换中使用此事件,以在子会话终止时强制父状态退出。最后,父状态和子状态可以通过 相互通信<send>。parent 可以使用<send>withtarget属性设置 to_invoke_invokeid与 child 进行通信,child 可以通过<send>with targetattribute set to与 parent 进行通信_parent

现在,关于你的问题:

当事件被调用时,这个调用元素会更新数据模型元素。

我认为您对此概念化的方式可能存在问题,因为调用的会话有自己的数据模型(也就是说,它自己的内存)。您可以使用 绑定子会话的初始数据模型值<param>,但您不能真正在父会话和子会话之间共享内存。这意味着您不能使用例如<assign><script>标签直接在子会话中更新父会话中的数据模型。

子会话在父会话中更新数据模型的唯一方法是通过传递事件(例如<send event="update" target="_parent"><param name="dataToUpdate" expr="dataToUpdate"/></send>)与父会话通信。然后,父级需要一个<transition>元素,以便它可以处理从子会话发送的事件,例如<transition event="update"><assign location="dataToUpdate" expr="_event.dataToUpdate"/></transition>.

这就引出了一个问题,即<invoke>定期更新数据模型是否是最好、最简单的方法。例如,将数据模型更新逻辑放在<parallel>状态子级中可能会更简单。这样,您可以使用<assign>直接更新数据模型。

我怎样才能使这种情况定期发生?例如,是否可以每秒定期调用此调用?或者也许每秒都过渡到事件?

要定期调用会话,您将进入和退出包含<invoke> 元素的状态。以下(未经测试的)代码可能会起作用:

<state id=invokeParent">
  <!-- this is some data that you want the child session to update in the parent session -->
  <datamodel>
    <data id="dataToUpdate" />
  </datamodel>
  <onentry>
    <send event="loop" delay="1s"/> <!-- send the 'loop' event every second to loop in invokeParent -->
  </onentry>
  <transition event="loop" target="invokeParent" /> <!-- this transition will exit and re-enter the state, restarting the invoked session -->
  <transition event="done.invoke.myInvoke" target="invokeParent" /> <!-- also loop if the invoked session terminates -->
  <invoke id="myInvoke" type="scxml" src="file:test276sub1.scxml"/> <!-- this is the invoke -->
  <!-- this targetless transition handles the update event sent from the child session to the parent to update the parent's datamodel -->
  <transition event="update">
    <assign location="dataToUpdate" expr="_event.dataToUpdate"/>
  </transition>
</state>

后者的问题是,如果我在调用的 finalize 部分放置一个转换,调用它自己,它似乎不会多次调用调用部分。

我不相信transition是 的合法孩子finalizefinalize旨在包含可执行内容(例如scriptassign),这些内容允许您在子会话发送的事件被父会话处理之前对其进行操作。

https://www.w3.org/TR/scxml/#finalize


推荐阅读