Сначала я хотел предоставить фон <invoke>
.<invoke>
ставится как ребенок на <state>
.Он запускает сеанс дочернего конечного автомата при входе в состояние и останавливает сеанс при выходе из состояния.Кроме того, если дочерний сеанс переходит в состояние <final>
, то в родительский сеанс отправляется событие done.invoke.invokeid
.Это событие done.invoke.invokeid
можно использовать при переходе в родительское состояние, чтобы принудительно завершить родительское состояние после завершения дочернего сеанса.Наконец, родительское и дочернее состояния могут связываться друг с другом через <send>
.Родитель может общаться с ребенком, используя <send>
с атрибутом target
, установленным на _invoke_invokeid
, а ребенок может общаться с родителем через <send>
с атрибутом target
, установленным на _parent
.
Теперь на ваши вопросы:
Этот элемент invoke обновляет элементы datamodel при вызове события.
Я думаю, что может быть проблема с тем, как вы это поняли, потому что вызванный сеанс имеет свою собственную модель данных (то есть, свою собственную память).Вы можете связать начальные значения модели данных дочернего сеанса, используя <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 вызова, вызывающего себя, он, похоже, не работаетвызывайте секцию invoke более одного раза.
Я не верю, что transition
является законным потомком finalize
.finalize
должен содержать исполняемый контент (например, script
, assign
), который позволяет вам манипулировать событиями, отправленными дочерним сеансом, до того, как они будут обработаны родительским сеансом.
См. https://www.w3.org/TR/scxml/#finalize