Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/heisenware/fsm-async
Simple asynchronous state machine providing hooks that are triggered when having reached a state.
https://github.com/heisenware/fsm-async
fsm-async state-machine
Last synced: about 1 month ago
JSON representation
Simple asynchronous state machine providing hooks that are triggered when having reached a state.
- Host: GitHub
- URL: https://github.com/heisenware/fsm-async
- Owner: heisenware
- Created: 2017-07-17T14:05:17.000Z (over 7 years ago)
- Default Branch: master
- Last Pushed: 2024-06-16T16:39:10.000Z (7 months ago)
- Last Synced: 2024-11-01T12:16:55.158Z (2 months ago)
- Topics: fsm-async, state-machine
- Language: JavaScript
- Homepage:
- Size: 59.6 KB
- Stars: 13
- Watchers: 3
- Forks: 3
- Open Issues: 2
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
Awesome Lists containing this project
README
# fsm-async
[![Build Status](https://travis-ci.com/heisenware/fsm-async.svg?branch=master)](https://travis-ci.com/heisenware/fsm-async)
[![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/heisenware/fsm-async/master/LICENSE)
[![Semver](https://img.shields.io/badge/semver-2.0.0-blue)](https://semver.org/spec/v2.0.0.html)
[![GitHub Releases](https://img.shields.io/github/tag/heisenware/fsm-async.svg)](https://github.com/heisenware/fsm-async/tag)
[![GitHub Issues](https://img.shields.io/github/issues/heisenware/fsm-async.svg)](http://github.com/heisenware/fsm-async/issues)A state machine implementation featuring:
1. `on` life-cycle events, allowing the triggering of further (internal)
events during the callback.2. `async` event functions that can be awaited. Depending
on the implemented logic, multiple state changes can be awaited.3. Generic and awaitable `waitUntilStateEnters()` and
`waitUntilStateLeaves()` functions providing full flexibility to
state machine clients business logic.## Example
Define the transition table as a json object,
```javascript
const transitionTable = {
initial: 'disconnected',
transitions: [
{ ev: 'connect', from: 'disconnected', to: 'connecting' },
{ ev: '_connectDone', from: 'connecting', to: 'connected' },
{ ev: 'disconnect', from: 'connected', to: 'disconnecting' },
{ ev: '_disconnectDone', from: 'disconnecting', to: 'disconnected' }
]
}
```then apply this logic to your object:
```javascript
const StateMachine = require('fsm-async')class MyClient extends StateMachine {
constructor () {
const transitionTable = {
initial: 'disconnected',
transitions: [
{ ev: 'connect', from: 'disconnected', to: 'connecting' },
{ ev: '_connectDone', from: 'connecting', to: 'connected' },
{ ev: 'disconnect', from: 'connected', to: 'disconnecting' },
{ ev: '_disconnectDone', from: 'disconnecting', to: 'disconnected' }
]
}
super(transitionTable)
}
}
```This injects the events as proper callable functions to your instance,
hence you can write:```javascript
myClient = new MyClient()
myClient.connect()
```In the body of your class you can define life-cycle functions `on` and
`on`, which are automatically called and can be used to trigger
further events:```javascript
const StateMachine = require('fsm-async')class MyClient extends StateMachine {
constructor () {
const transitionTable = {
initial: 'disconnected',
transitions: [
{ ev: 'connect', from: 'disconnected', to: 'connecting' },
{ ev: '_connectDone', from: 'connecting', to: 'connected' },
{ ev: 'disconnect', from: 'connected', to: 'disconnecting' },
{ ev: '_disconnectDone', from: 'disconnecting', to: 'disconnected' }
]
}
super(transitionTable)
}// Use async here to be able to await internally
async onConnecting () {
// Simulate connection establishment
await new Promise(resolve => setTimeout(resolve, 1000))
// Internally trigger an event bringing the machine to connected state
this._connectDone()
}async onDisconnecting () {
// Simulate disconnection
await new Promise(resolve => setTimeout(resolve, 1000))
// Internally trigger an event bringing the machine to disconnected state
this._disconnectDone()
}
}
```Now, outer code can `await` the `connect()` of your client and/or use other
utility functions injected by the `StateMachine`. The utility functions are:
1. `getState()` returns current state
2. `waitUntilStateEnters()` waits until a given state is entered
3. `waitUntilStateLeaves()` waits until a given state is left
4. `onStateChange()` notifies about state changes
5. `onInvalidTransition()` notifies about invalid transitionsThe `StateMachine` class at the same time is an event emitter. Hence,
```
stateMachine.on('state', )
stateMachine.on('invalidTransition', )
```
is also possible.Please see the provided example code (`examples` folder) for more details and
usage patterns.You can run the example code via:
```
npm run example
```