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
for state specification.

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
that targets the

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
.

‘target’ specifies the transformation for the default history configuration. It only happens once. In standards-compliant SCXML documents, this transformation must not contain a “cond” or “event” attribute, and a non-empty “target” must be specified. This transformation may contain executable content. If ‘type’ is’ shallow ‘, then the ‘target’ of the
must contain only the immediate children of the parent state. Otherwise, it must contain only the offspring of the parent.

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
, children can only contain executable content.

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 thenameIn the top-level data declaration with the calling session<data>Elements of theidIf 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.namelistSimilar. If the key value in the name list is in the top-level data model of the calling session<data>Elements of theidTo 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 eventdone.invoke.idOn 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 receivedone.invokePreviously 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.idEvents. 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