1. Pre-instructions
This time, let me explain my view of the state diagram. While state diagrams have a number of advantages (see the previous article), if you want to use them, it is appropriate to model the complex parts of a project if you want to do a full state diagram for an entire old project. If you have the energy, you can try to state map the entire project.
1.1 state diagram
Let me remind you what a state diagram is. The predecessor of the state graph is FSM. Some problems may be exposed during FSM use, such as:
- State explosion
- Weak hierarchical expression ability
When the project is complicated, the FSM will be difficult to maintain at a later stage.
In response to these problems, computer scientist David Harel extended FSM in 1984 and invented the state graph (SC) to solve the problems in FSM. (Thesis Address)
SC not only visualizes FSM better, it’s also executable. Most of today’s state machine libraries are, more specifically, state diagram libraries.
SC is defined as a hierarchical directed graph (S, T, R, In, Out), which has an additional R (Orthogonal) concept than FSM.
SC has designed a very complex and precise notation system that enhances the ability to express structural levels and connected expressions of directed graphs. It is currently the preferred control model for UML.
1.2 SCXML
SCXML stands for State Chart XML and is used to control abstract State machine representations.
SCXML is a set of specifications based on the David Harel status diagram and CCXML (Call Control eXtensible Markup Language) mentioned above.
After 10 years of customization from 2005 to 2015, the specification became a W3C recommendation. Most current programming language state machine tools are implemented based on this specification.
1.3 XState
XState is a front-end state graph tool library developed by Microsoft engineer David Khourshid. It is currently the most Star in the front-end state machine, and I feel very good after experiencing it (I am very happy to contribute 14.7K rows in this warehouse). Here is the XState Github Star record:
2. Organization description
XState written document is not accessible, many concept jumped (of course Most foreign documents have this problem, the author must be very want to express clearly, but it is not easy to do), if the reader of the state machine not the concept, the sudden a bunch of new concepts will let you off guard, learning curve, also don’t know how to use in the hand.
If you want to better understand and organize these concepts, it might be appropriate to compare them with SCXML and XState.
2.1 Organization of SCXML
There are mainly the following parts:
- The core
<scxml>
<state>
<transition>
<initial>
<parallel>
<final>
<history>
<onentry>
<onexit>
- Executable content
<raise>
<foreach>
<log>
<if>
<elseif>
<else>
- Data models and data operations
<datamodel>
<data>
<content>
<param>
<donedata>
<script>
<assign>
- External communication
<send>
<cancel>
<invoke>
<finalize>
2.2 Organization of XState
There are mainly the following parts:
- Machine
- State
- State Node
- Event
- Transition
- Parallel State
- Final State
- History State
- Effects
- Invoke
- Actions
- send
- raise
- respond
- forwardTo
- escalate
- log
- choose
- pure
- assign
- Activities
- Context
- Guard
- Delay
- Interpret
- Identify
- Actor
- Model
3. Correspondence
The following takes SCXML as the main line to do the corresponding description.
3.1 Core Elements
According to the classification of SCXML, the corresponding description is made from the elements of the core part first.
3.1.1 <scxml>
< SCXML >, the outermost state machine wrapping element, carries version information, and the state machine is made up of its children.
The attribute fields are described as follows:
The name of the | mandatory | Attribute constraints | type | The default value | Valid values | describe |
---|---|---|---|---|---|---|
initial | false | none | IDREFS | none | A valid state specification | Id of the initial state of the state machine. If not specified, the default initial state is the first substate in the document order |
name | false | none | NMTOKEN | none | Any valid NMTOKEN | The name of this state machine. It is purely informative |
xmlns | true | none | URI | none | www.w3.org/2005/07/scx… | |
version | true | none | decimal | none | Must be “1.0” | |
datamodel | false | none | NMTOKEN | platform-specific | “Null “,” ECMAScript “, “xpath” or any other platform-defined value | The data model required for this document. “Null” means null data model, “ECMAScript” means ECMAScript data model, and “xpath” means xpath data model |
binding | false | none | enum | “early” | “early”, “late” | The data binding to use |
Children can include:
<state>
<parallel>
<final>
<datamodel>
<script>
Corresponding XState is Machine, and some attributes of Machine are described as follows (details) :
{
"id": ""."initial": ""."context": {},
"states": {}}Copy the code
3.1.2 <state>
, used to describe the state in the state machine.
<scxml name="State machine" version="1.0" xmlns="http://www.w3.org/2005/07/scxml">
<state id="A state"/>
</scxml>
Copy the code
The attribute fields are described as follows:
The name of the | mandatory | Attribute constraints | type | The default value | Valid values | describe |
---|---|---|---|---|---|---|
id | false | none | ID | none | State ID | |
initial | false | Must not be specified with an element. It must never appear as an atom. | IDREFS | none | The default initial state of this state |
Children can include:
<onentry>
<onexit>
<transition>
<initial>
<state>
<parallel>
<final>
<history>
<datamodel>
<invoke>
State Node corresponding to XState. However, a State Node is an attribute consisting of multiple elements of an SCXML. Consists of
,
, < PARALLEL >,
,
.
Some attributes of a State Node are described as follows:
{
"id": ""."states": {},
"invoke": {},
"on": {},
"onEntry": {},
"onExit": {},
"onDone": {},
"always": {},
"after": {},
"tags": []."type": ""
}
Copy the code
Example:
Machine({
id: "State machine".states: {state A: {id: "A state",}}})Copy the code
3.1.3 <transition>
Transitions between states. Triggered by an event and converted by a condition judgment.
<scxml name="State machine" version="1.0" xmlns="http://www.w3.org/2005/07/scxml">
<state id="Open">
<transition cond="_event.data==1" event="Click" target="Closed" />
</state>
<state id="Closed" />
</scxml>
Copy the code
The attribute fields are described as follows:
The name of the | mandatory | Attribute constraints | type | The default value | Valid values | describe |
---|---|---|---|---|---|---|
event | false | EventsTypes.datatype | none | A whitespace delimited list of event descriptors | List of event indicators that trigger this transformation | |
cond | false | Boolean expression | ‘true’ | Boolean expression | Transition conditions | |
target | false | IDREFS | none | The state to jump to | Identifier of the state or parallel region to be converted to | |
type | false | enum | “external” | “internal” “external” | Determine whether the target state comes from an internal or external transition |
Children can contain executable content.
Corresponding to XState Event, Transition, and Guard. Some attributes are described as follows (details) :
{
"on": {
"": {},
"*": {},
"Custom Events": {
"target": "Target state"."cond": "Conditional judgment"."actions": "Executable content"."in": "Can only come from this state."."internal": "Internal conversion"."meta": {},
"description": ""}}}Copy the code
Example:
Machine({
id: "State machine".states: {open: {on: {Click: {target: "Closed".cond: (ctx, event) = > event.data == 1,},},}, close: {},},});Copy the code
3.1.4 <initial>
, which represents the default initial state of a complex element (that is, an element that contains children or elements). It’s not a state, it’s just an action that points to a state.
<scxml name="State machine" version="1.0" xmlns="http://www.w3.org/2005/07/scxml">
<state id="Open">
<initial>
<transition target="Written" />
</initial>
<state id="Written" />
<state id="Read" />
</state>
</scxml>
Copy the code
Must be used with
Children includes
XState can be implemented directly in initail of a State Node.
Example:
Machine({
id: "State machine".states: {open: {initial: "Read".states: {
读取: {},
写入: {},
},
},
},
});
Copy the code
3.1.5 <parallel>
This element represents a state, and its children are executed in parallel. When the parent element is active, children are active at the same time.
<scxml name="State machine" version="1.0" xmlns="http://www.w3.org/2005/07/scxml">
<parallel id="The cloud">
<state id="Written" />
<state id="Read" />
</parallel>
</scxml>
Copy the code
The attribute fields are described as follows:
The name of the | mandatory | Attribute constraints | type | The default value | Valid values | describe |
---|---|---|---|---|---|---|
id | false | none | ID | none | Valid ID defined in XML Schema | State ID |
Children can include:
<onentry>
<onexit>
<transition>
<state>
<parallel>
<history>
<datamodel>
<invoke>
XState can be implemented directly in State Node type: parallel.
Example:
<scxml name="State machine" version="1.0" xmlns="http://www.w3.org/2005/07/scxml" initial="The cloud">
<parallel id="The cloud">
<state id="Upload">
<initial>
<transition target="Free" />
</initial>
<state id="Free">
<transition target="Up in" event="Start" />
</state>
<state id="Up in">
<transition target="Success" event="完在" />
</state>
<state id="Success"></state>
</state>
<state id="Download">
<initial>
<transition target="Download. Free." />
</initial>
<state id="Download. Free.">
<transition target="Download. Downloading." event="Start" />
</state>
<state id="Download. Downloading.">
<transition target="Download. Success." event="完在" />
</state>
<state id="Download. Success."></state>
</state>
</parallel>
</scxml>
Copy the code
Machine({
id: "State machine".initial: "The cloud".states: {Web disk: {type: "parallel".statesDownload: {initial: "Free".states: {idle: {on: {start:"Downloading",},}, download: {on: {complete:"Success",},}, success: {},},}, upload: {initial: "Free".states: {idle: {on: {start:"Up in",},}, on: {on: {complete:"Success",},}, success: {},},},},},},},});Copy the code
3.1.6 <final>
represents the final state of the < SCXML > or compound
element.
<scxml name="State machine" version="1.0" xmlns="http://www.w3.org/2005/07/scxml">
<state id="Downloading">
<transition event="Complete" target="Success" />
</state>
<final id="Success" />
</scxml>
Copy the code
The attribute fields are described as follows:
The name of the | mandatory | Attribute constraints | type | The default value | Valid values | describe |
---|---|---|---|---|---|---|
id | false | none | ID | none | Valid ID defined in XML Schema | State ID |
Children can include:
<onentry>
<onexit>
<donedata>
XState can be specified directly in State Node type: final.
Example:
<scxml name="State machine" version="1.0" xmlns="http://www.w3.org/2005/07/scxml">
<initial>
<transition target="Work" />
</initial>
<state id="Work">
<initial>
<transition target="Working on a mission." />
</initial>
<! When the child state is final, the parent state raises the don.state event.
<transition event="Work done. The state." target="Job done" />
<state id="Working on a mission.">
<transition event="Complete" target="Mission accomplished." />
</state>
<final id="Mission accomplished."></final>
</state>
<final id="Job done" />
</scxml>
Copy the code
Machine({
id: "State machine".initial: "Work".states: {work: {initial: "Working on a mission.".states: {Completing a task: {on: {complete:"Mission accomplished.",},}, task completed: {type: "final",}},onDone: "Job done",}, work done: {},},});Copy the code
3.1.7 <history>
Pseudo state allows the state machine to remember its state configuration. A
state returns the state machine to the configuration of this record.
<scxml name="State machine" version="1.0" xmlns="http://www.w3.org/2005/07/scxml">
<history id="Historical state" type="shallow">
<transition target="A state" />
</history>
<state id="A state"></state>
</scxml>
Copy the code
The attribute fields are described as follows:
The name of the | mandatory | Attribute constraints | type | The default value | Valid values | describe |
---|---|---|---|---|---|---|
id | false | none | ID | none | Valid ID defined in XML Schema | State ID |
type | false | none | enum | “shallow” | “Deep” or “shallow” | Determines whether to record the child state of the active atom in the current state or only its immediate child state. |
Children can include
XState can be specified directly in State Node type: history. Added some additional attributes:
{
"type": "history"."history": "shallow"."target": "Default to parent state"
}
Copy the code
Example:
<scxml name="State machine" version="1.0" xmlns="http://www.w3.org/2005/07/scxml" initial="New">
<state id="New">
<initial>
<transition target="In writing"></transition>
</initial>
<transition target="Break" event="Pause"></transition>
<state id="In writing">
<transition target="Preview" event="Next step"></transition>
</state>
<state id="Preview">
<transition target="Submitted" event="Next step"></transition>
</state>
<state id="Submitted"></state>
<history id="Historical state" type="shallow"></history>
</state>
<state id="Break">
<transition target="Historical state" event="Recovery"></transition>
</state>
</scxml>
Copy the code
Machine({
id: "State machine".initial: "New".states: {
新建: {
initial: "In writing".on: {pause:"Break",},states: {in writing: {on: {
下一步: "Preview",},}, preview: {on: {
下一步: "Submitted",},}, submitting: {}, historical status: {type: "history",},},}, interrupt: {on: {restore:"New.history Status",},},},});Copy the code
3.1.8 <onentry>
< onEntry >, a wrapper element that contains executable content to execute when entering the state.
<scxml name="State machine" version="1.0" xmlns="http://www.w3.org/2005/07/scxml" initial="A state">
<state id="A state">
<onentry>
<log expr="' Welcome to state A'" />
</onentry>
</state>
</scxml>
Copy the code
Like
XState can be defined directly in onEntry of the State Node.
Example:
Machine({
id: "State machine".initial: "A state".states: {state A: {onEntry: actions.log("Welcome to state A."),}}});Copy the code
3.1.9 <onexit>
< onExit >, a wrapper element that contains executable content to execute when exiting the state.
<scxml name="State machine" version="1.0" xmlns="http://www.w3.org/2005/07/scxml" initial="A state">
<state id="A state">
<onexit>
<log expr="' Welcome to state A next time." />
</onexit>
</state>
</scxml>
Copy the code
Similarly, children can only contain executable content.
XState can be defined directly in the onExit of a State Node.
Example:
Machine({
id: "State machine".initial: "A state".states: {state A: {onExit: actions.log("Welcome to state A next time."),}}});Copy the code
3.2 Executable Content
Executable content that can only be used in < onEntry >,
, and < Transition >. It provides hooks that allow AN SCXML session to modify its data model and interact with external entities.
It includes not only
,
,
,
,
, and
, but also
In XState, all the “executables” in SCXML are collectively referred to as actions. So the corresponding “executables” are in the XState Actions package.
3.2.1 <raise>
The
element raises an event in the current SCXML session. Events in < Transition > can be triggered.
<scxml name="State machine" version="1.0" xmlns="http://www.w3.org/2005/07/scxml" initial="A state">
<state id="A state">
<onentry>
<raise event="Jump" />
</onentry>
</state>
</scxml>
Copy the code
The attribute fields are described as follows:
The name of the | mandatory | Attribute constraints | type | The default value | Valid values | describe |
---|---|---|---|---|---|---|
event | true | NMTOKEN | none | Specifies the name of the event. This will match the “Event” attribute of the transformation. |
The actions. Raise function corresponding to XState. Example:
<scxml name="State machine" version="1.0" xmlns="http://www.w3.org/2005/07/scxml" initial="A state">
<state id="A state">
<transition target=State of "B" event="Jump"></transition>
<onentry>
<raise event="Jump" />
</onentry>
</state>
<state id=State of "B"></state>
</scxml>
Copy the code
Machine({
id: "State machine".initial: "A state".states: {state A: {onEntry: actions.raise("Jump"),
on: {jump:State of "B",
},
},
状态B: {},
},
});
Copy the code
3.2.2 <foreach>
The
element allows the SCXML application to traverse the collection in
and execute the executable content contained within it foreach item in the collection.
<scxml name="State machine" version="1.0" xmlns="http://www.w3.org/2005/07/scxml" initial="A state">
<datamodel>
<data expr="[10, 20, 30]" id="dataArr" />
</datamodel>
<state id="A state">
<onentry>
<foreach array="dataArr" index="varIndex" item="varItem">
<log expr="varIndex" />
<log expr="varItem" />
</foreach>
</onentry>
</state>
</scxml>
Copy the code
The attribute fields are described as follows:
The name of the | mandatory | Attribute constraints | type | The default value | Valid values | describe |
---|---|---|---|---|---|---|
array | true | Value expression | none | Evaluates to a value expression for an iterable set<foreach> |
Element iterates over a shallow copy of the collection | |
item | true | xsd:string | none | In the specified number<datamodel> The name of any variable that is valid in |
A variable that stores different items of the collection in each iteration of the loop | |
index | false | xsd:string | none | In the specified number<datamodel> The name of any variable that is valid in |
Each iteration of the foreach loop stores the variable of the current iteration index |
Children consists of one or more executable content.
This can correspond to XState’s actions.pure function, which can return one or a group of actions, or nothing at all. Of course, this function is more flexible. Example:
Machine({
id: "State machine".initial: "A state".context: {
dataArr: [10.20.30],},states: {state A: {onEntry: actions.pure((context, event) = > {
const _actions = [];
context.dataArr.map((varItem, varIndex) = > {
_actions.push(actions.log(varIndex.toString()));
_actions.push(actions.log(varItem.toString()));
});
return_actions; })},}});Copy the code
3.2.3 <log>
allows applications to generate logging or debug messages.
<scxml name="State machine" version="1.0" xmlns="http://www.w3.org/2005/07/scxml" initial="A state">
<state id="A state">
<onentry>
<log expr="' Welcome to state A'" />
</onentry>
</state>
</scxml>
Copy the code
The attribute fields are described as follows:
The name of the | mandatory | Attribute constraints | type | The default value | Valid values | describe |
---|---|---|---|---|---|---|
label | false | string | An empty string | A string with implementation-dependent interpretations. It is intended to provide metadata about the log string specified by “expr”. | ||
expr | false | Value expressions | none | An expression that returns the value to be recorded |
Corresponds to XState’s actions.log. Example:
Machine({
id: "State machine".initial: "A state".states: {state A: {onEntry: actions.log("Welcome to state A."),}}});Copy the code
3.2.4 <if>
,<elseif>
,<else>
is a container for conditional execution elements.
is an empty element that partitions the contents of
and provides a condition to determine whether partitioning is performed.
is an empty element that separates the contents of
. It is equivalent to an
with a “cond” that always evaluates to true.
<if cond="cond1">
<log expr="'cond1==true'" />
<elseif cond="cond2" />
<log expr="'cond2==true'" />
<elseif cond="cond3" />
<log expr="'cond3==true'" />
<else />
<log expr="' Other Circumstances '" />
</if>
Copy the code
The attribute fields are described as follows:
The name of the | mandatory | Attribute constraints | type | The default value | Valid values | describe |
---|---|---|---|---|---|---|
cond | true | Conditional expression | none | A valid conditional expression | A Boolean expression |
There are a number of methods in XState that implement similar capabilities, and if anything, the actions. Choose function. Example:
<scxml name="State machine" version="1.0" xmlns="http://www.w3.org/2005/07/scxml" initial="A state">
<datamodel>
<data expr="2" id="value" />
</datamodel>
<state id="A state">
<onentry>
<if cond="value == 1">
<log expr="'value === 1'" />
<elseif cond="value == 2" />
<log expr="'value === 2'" />
<else />
<log expr="'value ! = 1 && value ! = 2 '" />
</if>
</onentry>
</state>
</scxml>
Copy the code
Machine(
{
id: "State machine".initial: "A state".context: {
value: 2,},states: {state A: {onEntry: actions.choose([
{
cond: (context, event) = > context.value === 1.actions: [actions.log("value === 1")]}, {cond: "equal2".actions: [actions.log("value === 2")]}, {actions: [actions.log("value ! = 1 && value ! = 2"],},]),},},}, {guards: {
equal2: (context) = > context.value === 2,}});Copy the code
3.3 Data model and data manipulation
This part is the definition and manipulation of the data part outside of the state.
The datamodel is defined by the
element, which contains zero or more
elements, each of which defines a data element and assigns an initial value to it. These values can be specified online or loaded from an external source. They can then be updated with the
element. < doneData >,
, and
elements can be used to merge data into communication with external entities. Finally, the
3.3.1 <datamodel>
is a wrapper element that encapsulates any number of
elements, each of which defines a data object.
Children can only contain .
Corresponds to the top-level context of XState.
3.3.2 rainfall distribution on 10-12<data>
The element is the part that declares and populates the data model.
<datamodel>
<data expr="true" id="VarBool" />
<data expr="1" id="VarInt" />
<data expr="This is a string." id="VarString" />
</datamodel>
Copy the code
The attribute fields are described as follows:
The name of the | mandatory | Attribute constraints | type | The default value | Valid values | describe |
---|---|---|---|---|---|---|
id | true | ID | none | The name of the data item | ||
src | false | URI | none | Gives the location from which the data object should be retrieved | ||
expr | false | Expression | none | A valid conditional expression | Executes to provide the value of the data item |
In a standards-compliant SCXML document, a element can have either “SRC” or “expr” attributes, but not both. In addition, the element must not have children if either attribute exists. Therefore, ‘SRC’, ‘expr’, and children are mutually exclusive in the element.
Exists directly in XState as the value of the Context field.
Example:
<scxml name="State machine" version="1.0" xmlns="http://www.w3.org/2005/07/scxml" initial="A state">
<datamodel>
<data expr="true" id="VarBool" />
<data expr="1" id="VarInt" />
<data expr="This is a string." id="VarString" />
</datamodel>
<state id="A state">
<onentry>
<log expr="VarBool" />
<log expr="VarInt" />
<log expr="VarString" />
</onentry>
</state>
</scxml>
Copy the code
Machine({
id: "State machine".initial: "A state".context: {
varBool: true.varInt: 1.varString: "This is a string.",},states: {state A: {onEntry: [
actions.log((context) = > context.varBool),
actions.log((context) = > context.varInt),
actions.log((context) = > context.varString),
],
},
},
});
Copy the code
3.3.3 <assign>
The
element is used to modify the data model.
<assign location="Var1" expr="5"/>
Copy the code
The attribute fields are described as follows:
The name of the | mandatory | Attribute constraints | type | The default value | Valid values | describe |
---|---|---|---|---|---|---|
location | true | Path expression | none | A valid path expression | The location in the data model to insert a new value | |
expr | false | This attribute may not appear on a class that has child elements<assign> The element |
Value expression | none | A valid value expression | An expression that returns the value to be assigned |
In XState, use the actions. Assign function.
Example:
<scxml name="State machine" version="1.0" xmlns="http://www.w3.org/2005/07/scxml" initial="A state">
<datamodel>
<data expr="1" id="VarInt" />
<data expr="This is a string." id="VarString" />
</datamodel>
<state id="A state">
<onentry>
<assign expr="5" location="VarInt" />
<assign expr="' New string '" location="VarString" />
</onentry>
</state>
</scxml>
Copy the code
Machine({
id: "State machine".initial: "A state".context: {
varInt: 1.varString: "This is a string.",},states: {state A: {onEntry: actions.assign({
varInt: 5.varString: "New string",}),},},});Copy the code
We do<script>
The
<script>console.log('Hello, world! ')</script>
Copy the code
The attribute fields are described as follows:
The name of the | mandatory | Attribute constraints | type | The default value | Valid values | describe |
---|---|---|---|---|---|---|
src | false | This may not happen if the element has child elements | none | Effective URI | Give the location where the script should be downloaded |
The children content of the
XState can express similar capabilities in many places. For example, the actions attribute supports direct assignment functions, and similar capabilities can be implemented in actions. Log, actions.
3.3.5 <donedata>
A wrapper element that holds the data to be returned when entering the
state.
<final id="Final state">
<donedata>
<param expr="'value1'" name="key1" />
<param expr="'value2'" name="key2" />
</donedata>
</final>
Copy the code
Children can include:
<content>
: Can occur 0 or 1 times.<param>
: Can occur 0 or more times.
A standards-compliant SCXML document must specify a single
element or one or more
elements as child elements of
, but not both. If the SCXML processor generates a “done” event when it enters the final state, it must execute the < doneData > element
or < Content > child element and place the resulting data in the _event.data field.
The data property field corresponding to the XState State Node.
Example:
<scxml name="State machine" version="1.0" xmlns="http://www.w3.org/2005/07/scxml" initial="A state">
<state id="A state" initial="State of A1">
<transition target=State of "B" event="Is done. The state. The state of A">
<log expr="_event.data"></log>
</transition>
<final id="State of A1">
<donedata>
<param expr="1" name="finalCustomeData1" />
<param expr="2" name="finalCustomeData2" />
</donedata>
</final>
</state>
<state id=State of "B"></state>
</scxml>
Copy the code
Machine({
id: "State machine".initial: "A state".context: {},
states: {state A: {initial: "State of A1".onDone: {
actions: actions.log((context, event) = > {
return event.data;
}),
target: State of "B",},states: {state A1: {type: "final".data: {
finalCustomeData1: 1.finalCustomeData2: 2,},},},}, state B: {},},});Copy the code
3.3.6 <param>
The tag provides a generic way to identify keys and dynamically computed values that can be passed to external services or included in events.
<final id="Final state">
<donedata>
<param expr="'value1'" name="key1" />
<param expr="'value2'" name="key2" />
</donedata>
</final>
Copy the code
The attribute fields are described as follows:
The name of the | mandatory | Attribute constraints | type | The default value | Valid values | describe |
---|---|---|---|---|---|---|
name | true | NMTOKEN | none | string | ||
expr | false | Value expressions | none | Effective value expression | ||
location | false | Position expression | none | Effective position expression |
Event data is defined in a manner similar to one key one value.
XState is flexible; you can simply fill in Object at the event return.
3.3.7 <content>
The container element that contains data to be passed to the external service.
<final id="Final state">
<donedata>
<content>{key1: 'value1', key2: 'value2'}</content>
</donedata>
</final>
Copy the code
The attribute fields are described as follows:
The name of the | mandatory | Attribute constraints | type | The default value | Valid values | describe |
---|---|---|---|---|---|---|
expr | false | May not appear with child content | Value expressions | none | Effective value expression |
If the “expr” attribute is not present, the processor must use child elements of
as output.
Define event data in a manner similar to an Object. The function is similar to . It can be used in < doneData >,
,
.
XState is flexible; you can simply fill in Object at the event return.
3.4 External Communication
The external communication capability allows an SCXML session to send and receive events from external entities and invoke external services.
3.4.1 track<send>
is used to send events and data to external systems, including external SCXML interpreters, or to raise events in the current SCXML session. Provide “fire and forget” capabilities.
<scxml name="State machine" version="1.0" xmlns="http://www.w3.org/2005/07/scxml" initial="A state">
<state id="A state">
<onentry>
<send event="Jump" />
</onentry>
</state>
</scxml>
Copy the code
The attribute fields are described as follows:
The name of the | mandatory | Attribute constraints | type | The default value | Valid values | describe |
---|---|---|---|---|---|---|
event | false | Must not appear with “eventExpr” | EventType.datatype | none | A string indicating the name of the message being generated | |
eventexpr | false | Do not appear with “event” | Value expressions | none | Dynamic alternative to “event”. If this attribute is present, the SCXML processor must execute the parent<send> Element, and treats the result as if it had been entered as the value of “event. |
|
target | false | Cannot appear with “targetExpr” | URI | none | A valid target URI | Unique identifier of the message target to which the platform should send the event |
targetexpr | false | Cannot appear with “target” | Value expressions | none | An expression for a valid destination URI | Dynamic alternative to “Target”. If this attribute is present, the SCXML processor must execute the parent<send> Element, and treats the result as if it had been entered as a value for “target. |
type | false | Cannot appear together with typeExpr | URI | none | The URI that identifies the message transport mechanism | |
typeexpr | false | Cannot appear with “type” | Value expressions | none | Dynamic alternative to “type”. If this attribute is present, the SCXML processor must execute the parent<send> Element, and treats the result as if it had been entered as a “type” value |
|
id | false | Must not appear together with “idlocation” | xml:ID | none | Will be used as the<send> String literal for the identifier of the instance |
|
idlocation | false | Must not appear with “ID” | Position expression | none | Any location expression executes as a data model location that can store the system-generated ID | |
delay | false | Cannot appear with “delayExpr” or property “target” with value “_internal” | Duration.datatype | none | Indicates how long the processor should wait before dispatching a message | |
delayexpr | false | Cannot occur when delay or property target has a value of _internal | Value expressions | none | Dynamic alternative to “Delay”. If this attribute is present, the SCXML processor must execute the parent<send> Element, and treats the result as if it had been entered as a “delay” value |
|
namelist | false | Not with<content> Element specified together |
List of positional expressions | none | A space-separated list of one or more data model locations, included in the message as property/value pairs. (The names of locations are properties, and values stored at locations are values.) |
Children can include:
<content>
: Can occur 0 or 1 times.<param>
: Can occur 0 or more times.
Conforming SCXML documents must specify exactly one of “event”, “eventExpr”, or
. Conforming documents must not specify “namelist” or “param>” in
.
- The SCXML processor must contain
<param>
Or ‘namelist’ provides all properties and values, even if duplicates occur. - If “IDLocation” exists, the SCXML processor must execute the parent
<send>
Element to generate an ID and store it in this location. - If the delay is specified by “delay” or “delayexpr,” the SCXML processor must interpret the string as an interval of time. It must send messages only after the delay interval has passed. (Note that the execution of the send flag returns immediately.) The processor must be executing
<send>
Element when all parameters are executed to<send>
, rather than when the message is actually sent. If the execution of the argument produces an error, the processor must discard the message without attempting to deliver it. If the SCXML session terminates before the delay interval passes, the SCXML processor must discard the message without attempting to deliver it.
The actions. Send function corresponding to XState. Similar structure:
{
"event": "scxml.event"."options": {
"id": "scxml.id"."delay": "scxml.delay"."to": "scxml.target"}}Copy the code
Example:
<scxml name="State machine" version="1.0" xmlns="http://www.w3.org/2005/07/scxml" initial="A state">
<state id="A state">
<transition target=State of "B" event="Jump"></transition>
<onentry>
<send event="Jump" />
</onentry>
</state>
<state id=State of "B"></state>
</scxml>
Copy the code
Machine({
id: "State machine".initial: "A state".states: {state A: {onEntry: actions.send("Jump"),
on: {jump:State of "B",
},
},
状态B: {},
},
});
Copy the code
3.4.2 <cancel>
The
element is used to cancel a delayed
event. The SCXML processor must not allow < Cancel > to affect events that are not raised in the same session. The processor should do its best to cancel all delayed events with the specified ID. Note, however, that it does not guarantee success, for example, if the event has already been delivered by the time the < Cancel > tag is executed.
<scxml name="State machine" version="1.0" xmlns="http://www.w3.org/2005/07/scxml" initial="A state">
<state id="A state">
<onentry>
<cancel sendid="Jump ID" />
</onentry>
</state>
</scxml>
Copy the code
The attribute fields are described as follows:
The name of the | mandatory | Attribute constraints | type | The default value | Valid values | describe |
---|---|---|---|---|---|---|
sendid | false | May not appear with sendideexpr | IDREF | none | Delay the sendid of the event | ID of the event to cancel. If multiple delayed events have this SenDID, the handler cancels all of them |
sendidexpr | false | Do not appear with Sendid | Value expressions | none | Any expression that evaluates to a delayed event ID | Dynamic alternative to ‘sendid’. If this attribute is present, the SCXML processor must execute the parent<cancel> Element, and treats the result as if it had been entered as the value of “senDID” |
The actions. Cancel function corresponding to XState.
Example:
<scxml name="State machine" version="1.0" xmlns="http://www.w3.org/2005/07/scxml" initial="Not logged in">
<state id="Not logged in">
<transition target="Logged in" event="Login"></transition>
</state>
<state id="Logged in">
<transition target="Logged in" event="Activity"></transition>
<onentry>
<send event="Cancel" delay="1000 * 60" target="Not logged in" id="ID" />
</onentry>
<onexit>
<cancel sendid="ID"></cancel>
</onexit>
</state>
</scxml>
Copy the code
Machine({
id: "State machine".initial: "Not logged in".states: {not logged in: {on: {login:"Logged in",
},
},
已登录: {
onEntry: actions.send("Cancel", {
delay: 1000 * 60.id: "ID",}).onExit: actions.cancel("ID"),
on: {logout:"Not logged in"Activity:"Logged in",},},},});Copy the code
This can also be done using XState’s after syntax sugar:
Machine({
id: "State machine".initial: "Not logged in".states: {not logged in: {on: {login:"Logged in",
},
},
已登录: {
after: {[1000 * 60] :"Not logged in",},on: {activity:"Logged in",},},},});Copy the code
Rule 3.4.3<invoke>
The
element is used to create an instance of the external service.
<invoke id="ID_SUB" src="sub.scxml">
<param expr="3" name="i_ID" />
</invoke>
Copy the code
< Invoke > provides a more tightly coupled form of communication, specifically the ability to trigger platform-defined services and pass data to them. It and its child < Finalize > are useful in simulating the state of external service behavior. The
element executes after the < onEntry > element of the state and causes the creation of an instance of the external service. The
and
elements and the ‘namelist’ attribute can be used to pass data to the service. When the parallel state simultaneously invokes the same external service, a separate instance of the external service is started. They can be distinguished by the ID associated with them. Similarly, an ID contained in an event returned from an external service can be used to determine which events are responses to which invocations. Each event returned will only be processed by < Finalize > in the state that called it, but that event will then be processed like any other event received by the state machine. Therefore, Finalize code can be considered as a pre-processing phase applied before events are added to the event queue. Note that this event is passed to all parallel states to check for transitions. Since the call is canceled when the state machine leaves the call state, it makes no sense to start the call in a state that will exit immediately. Thus, the
element executes when it enters state, but only after checking for eventless transitions and pending internal event-driven transitions. If any such enabled transitions are found, the transitions are executed immediately and the state exits immediately without triggering the call. Therefore, the invocation is triggered only when the state machine reaches a stable configuration, that is, a configuration in which it will stay while waiting for external events.
The attribute fields are described as follows:
The name of the | mandatory | Attribute constraints | type | The default value | Valid values | describe |
---|---|---|---|---|---|---|
type | false | Cannot appear with the “TypeExpr” property | URI | none | Specifies the URI of the external service type | |
typeexpr | false | Must not appear with the “type” attribute | Value expressions | none | Evaluates any value expression that results in a URI that will be a valid value for ‘type’ | Dynamic alternative to “type”. If this attribute is present, the SCXML processor must execute the parent<invoke> Element, and the result is entered as the value of “type. |
src | false | URI | none | The URI to pass to the external service | ||
srcexpr | false | Value expressions | none | Dynamic alternative to ‘SRC’. If this attribute is present, the SCXML processor must execute the parent<invoke> Element, and treats the result as if it had been entered as a value of “SRC” |
||
id | false | ID | none | Will be used as the<invoke> String literal for the identifier of the instance |
||
idlocation | false | Position expression | none | Any data model expression that evaluates a data model location | ||
namelist | false | List of positional expressions | none | A space-separated list of one or more data model locations to be passed as property/value pairs to the calling service. (The name of a location is an attribute, and the value stored by a location is a value.) | ||
autoforward | false | Boolean value | false | Flag indicating whether the event is forwarded to the calling process |
Children can include:
<content>
: Can occur 0 or 1 times.<param>
: Can occur 0 or more times.<finalize>
: Can occur 0 or 1 times.
When the AutoForward attribute is set to true, the SCXML processor must send an exact copy of every external event it receives to the calling process. The SCXML processor must forward the event when it is removed from the external event queue of the calling session for processing.
External services may return multiple events during processing. If there is a < Finalize > handler ina < Invoke > instance that creates a service that generates an event, the SCXML processor must execute the code in that < Finalize > handler immediately before removing the event from the event queue for processing. It must not execute a < Finalize > handler in any other instance of
. Once the external service has finished processing, it must return a special event done.invoke.id to the external event queue of the calling process, where id is the call ID corresponding to the < Invoke > element. External services must not generate any additional events after this event completes.
<invoke>
The implementation of the
Including communication between parent and child processes is platform-specific, but the following requirements hold in the case of the called process itself being an SCXML session:
- if
<invoke>
In the<param>
Elements of thename
In the top-level data declaration with the calling session<data>
Elements of theid
If yes, the SCXML processor must be used<param >
Element as corresponding<data>
The initial value of the element. Top-level data declarations are included in<scxml>
The child element<datamodel>
Those declarations in the element. (Please note that this means in<data>
Any values specified in the element are ignored.namelist
Similar. If the key value in the name list is in the top-level data model of the calling session<data>
Elements of theid
To match, the SCXML processor must use the value of the key as the corresponding<data>
The initial value of the element. If the names do not match, the processor may not convert<param>
The value of the element or name list key/value pair is added to the data model of the calling session. However, the processor can make these values available in other platform-specific ways. - When the invoked state machine reaches its top-level final state, the handler must place the event
done.invoke.id
On the calling machine, where the external event queue ID is the call ID for this call. Note that reaching the top-level final state corresponds to normal termination of the machine, and once in this state, it cannot generate or process any further events. - As mentioned above, if the state machine is called upon to receive
done.invoke
Previously exited the state containing the call. Id event, which cancels the called session. The method of doing this is platform-specific. However, when it is cancelled, the called session must exit at the end of the next micro-step. The processor must execute a handler for all active states in the invoked session, but it cannot generatedone.invoke.id
Events. Once a called session is cancelled, the processor must ignore any events it receives from that session. In particular, it must not insert them into the external event queue of the calling session. - The SCXML processor must support communication between the calling session and the called session using the SCXML event I/O processor. The handler can support communication between the calling session and the called session using other event I/O handlers.
Corresponds to the Invoke property of the XState State Node. The description is as follows:
{
"id": ""."src": ""."autoForward": false."data": {},
"onDone": {},
"onError": {}}Copy the code
Example:
<scxml name="State machine" version="1.0" xmlns="http://www.w3.org/2005/07/scxml" initial="Waiting">
<state id="Waiting">
<transition event="Done.invoke. Child state machine" target="Time's up" />
<invoke id="Sub-state machine" type="http://www.w3.org/TR/scxml/">
<content>
<scxml name="Minute substate machine" version="1.0" xmlns="http://www.w3.org/2005/07/scxml" initial="Waiting" initial="Active">
<state id="Active">
<onentry>
<send delay="60s" event="The end"></send>
</onentry>
<transition target="Complete" event="The end"></transition>
</state>
<final id="Complete"></final>
</scxml>
</content>
</invoke>
</state>
<final id="Time's up"></final>
</scxml>
Copy the code
const minuteMachine = Machine({
id: "Minute substate machine".initial: "Active".states: {active: {after: {
60000: { target: "Complete"},},}, complete: {type: "final",}}}); Machine({id: "State machine".initial: "Waiting".states: {waiting: {invoke: {
src: minuteMachine,
onDone: "Time's up",},}, time up: {type: "final",}}});Copy the code
3.4.4 <finalize>
The < Finalize > element enables the calling session to update its data model with data contained in the events returned by the called session.
< Finalize > contains executable content to be executed when the external service returns an event after executing
. This content is applied before the system looks for a transform that matches the event. In executable content, the system variable “_event” can be used to reference data contained in the event being processed. In the case of parallel state, only finalize code in the original call state is executed. Any events that the state machine receives from the called component during the invocation are preprocessed by the < Finalize > handler before selecting the transformation. Finalize > code is used to normalize the form of the returned data and update the data model before the “event” and “cond” clauses of the transformation are performed. In compliant SCXML files, executable content in < finalise > must not raise events or invoke external actions. In particular, the
and
elements must not appear.
Children can contain executable content.
There is no CORRESPONDING API for XState, and XState is very flexible for processing messages, so this capability is built in.
Example:
<scxml name="State machine" version="1.0" xmlns="http://www.w3.org/2005/07/scxml" initial="Waiting">
<datamodel>
<data expr="1" id="VarValue" />
</datamodel>
<state id="Waiting">
<transition event="childToParent" cond="VarValue==2" target="The end" />
<invoke id="Sub-state machine" type="http://www.w3.org/TR/scxml/">
<content>
<scxml name="Send message to parent child state machine" version="1.0" xmlns="http://www.w3.org/2005/07/scxml" initial="Complete" initial="Active">
<final id="Complete">
<onentry>
<send target="#_parent" event="childToParent">
<param name="aParam" expr="2" />
</send>
</onentry>
</final>
</scxml>
</content>
<finalize>
<assign location="VarValue" expr="_event.data.aParam"/>
</finalize>
</invoke>
</state>
<final id="The end"></final>
</scxml>
Copy the code
3.5 There is no Corresponding XState API
The above corresponds to XState according to the specification. Some of them are XState features. As follows:
- Actor: Actor model, a very mature set of models. Used to extend substate machines.
- Interpreter: Because XState’s state machine is written as a pure set of functions, it has no side effects. So an Interpreter is officially provided to manage side effects.
- Model: Used to improve the developer experience, separate and organize contexts and events, and share models.
3.6 Corresponding large view
The overall corresponding relationship is roughly as shown in the figure below:
4. The last
It took more than a week to comb through and align the relationship between SCXML and XState, resulting in a 40,000-word article.
As an XState “experience”, this article from specification to tool correspondence is exactly what I needed most when I was confused at the beginning.
I also hope that this article can help students who are beginning to use state machines and XState to solve some doubts.
⭐ Github