34

Does anybody know of any javascript implementations of a state machine? My goal is to setup a state machine implementation that would bind events to state transitions. So, if a user clicks on a button then the state will be changed, and this state might define certain values in objects to be changed for example.

I want this to be a state machine simply because there will be a rules json file that will allow to dictate what values change of various objects when certain events are called. Because this will be structured within the file, I think it would be easy to parse that information into a state machine object.

jab
  • 5,673
  • 9
  • 53
  • 84

10 Answers10

37

There are two main libraries for a finite state machine in js :

1/ Machina: Very well documented, examples, supports two JavaScript message bus providers out of the box: postal.js and amplify.js.

2/ Javascript State Machine: simpler and easier to use, perfect for "basic" usages.

ansidev
  • 361
  • 1
  • 3
  • 17
Benibur
  • 816
  • 10
  • 9
6

I recently built a state machine implementation in JS, which is certainly the easiest to configure, thanks to its transition DSL:

transitions: [
  'next    : intro > form > finish',
  'back    : intro < form           < error',
  'error   :         form >           error',
  'restart : intro        < finish'
]

It's really flexible in both configuration and event handler assignment, you can add and remove states at runtime, pause and resume transitions, hook into a ton of events, with helpers for jQuery and reactive frameworks like Vue:

state-machine-demo

Docs and a whole host of demos here:

Dave Stewart
  • 2,324
  • 2
  • 22
  • 24
4

Little bit of promotion for my state machine: stateflow I just created my own state machine because i found none which was simple enough for me.

a flow is defined with a js object where the property is the state name and the value is another js object with following properties.

  • type: begin, end or state (default).
  • action: function with a State instance object set to this, can also be named action previously registered or another flow definition in this case it is a subflow.
  • on: property is to be matched event and value is the next state to goto

Simple example

var stateflow = require('stateflow');
var flow = new stateflow.StateFlow({
   a: {
       type:'begin',
       action: function(complete) {
           // do something
           complete('done');    
       },
       on: {
           done:'b',
           again:'a'
       }
   }, 
   b: {
       type:'end',
       action: function(complete) {
           complete('finished');
       }
   }
});
flow.start(function(event) {
   console.log('flow result:', event);
});

Check it out on git https://github.com/philipdev/stateflow or via npm

philipdev
  • 41
  • 1
3

Try taking a look at https://github.com/steelbreeze/state.js - it supports much of the state machine semantics as described in the UML 2 spec while still being performant. There's not much in the way of documentation yet, but the examples and tests should provide a good reference.

Mesmo
  • 1,890
  • 2
  • 15
  • 13
  • I have been using that library and I am very satisfied with it. We integrated it to our thingml approach (https://github.com/SINTEF-9012/ThingML) – bmorin Aug 27 '15 at 14:56
2

You'll find library designed with jQuery that seems to do what you're looking for and binding automatically the events for you:

1

My pick on this with the js-fsm micro library.

Features

  • State based FSM description. A state composed of a and an array of state transitions.
  • Transition from events. Multiple events define ORed events.
  • Transition from conditions. A condition is a key: value pair that should match on the condition object. Multiple key, value pairs defined ANDed conditions. Multiple conditions define ORed conditions
  • Each transition can optionally call actions or multiple actions. Actions can optionally have arguments or be members of this.
  • State machine could be mixed (as a mixin) to an existing object or a constructor's prototype. A method for this is provided.
  • State machine can optionally log if a log method exists on this or is provided.
  • AMD and Node modules are supported.
  • Unit tests with QUnit.

js-fsm github page.

basos
  • 578
  • 4
  • 11
1

I thought I would also talk about my own state machine library. I came to this SO question two years ago, and could not find anything that would fit my requirements, so I wrote state-transducer.

The key objectives for the API was :

  • functional API, entirely devoided of effect, with encapsulated internal state
  • generality and reusability (there is no provision made to accommodate specific use cases or frameworks)
  • it must be possible to add a concurrency and/or communication mechanism on top of the current design
  • it must be possible to integrate smoothly into React, Angular and your popular framework

It is used to modelize user interfaces, turning user flows

user flow

into state machines

fsm

user3743222
  • 18,345
  • 5
  • 69
  • 75
0

You may find this library of use:

https://www.npmjs.com/package/mistic

Disclaimer: I maintain it.

Ben Aston
  • 53,718
  • 65
  • 205
  • 331
0

AsyncMachine is another, less orthodox approach to state machine in JS (I'm the author). It's relational and supports multiple states being active simultaneously. Here's some code to answer your original question - after you click the button, there's side effects in terms of a new state and an attr on the context object:

const {
  machine
} = asyncmachine
// define states & relations
const state = {
  Clicked: {
    add: ['ShowFooter']
  },
  ShowFooter: {}
}
const example = machine(state)
// define handlers
example.Clicked_state = function() {
  this.timeout = setTimeout(
    this.dropByListener('Clicked'), 3000)
}

function render() {
  console.log('render')
  // get all the active state as class names
  const classes = example.is().join(' ')
  console.log(classes)
  document.getElementById('content').innerHTML = `
    <div class="${classes}">
      <button>CLICK</button>
      <footer>FOOTER</footer>
    </div>
  `
}
document.getElementById('content').addEventListener(
  'click', example.addByListener('Clicked'))
// bind render to any state change
example.on('tick', render)
render()
.Clicked button {
  background: red;
}

footer {
  display: none;
}

.ShowFooter footer {
  display: block
}
<script src="https://unpkg.com/asyncmachine@3.4.1/dist/asyncmachine.umd.js"></script>
<div id='content' />

There's also an inspector which can visualize the way your machine works (with time travel), eg:

enter image description here

Tobias Cudnik
  • 9,240
  • 4
  • 24
  • 18
0

I have used xtstate, It address almost all the concerns posted in the question. It has a great visualizer try it out.