Last active
July 27, 2023 10:32
-
-
Save whiteinge/0c5668ee565df6e9f21aef83f089dd2a to your computer and use it in GitHub Desktop.
Example of a Mealy state machine (initial pattern stolen from somewhere that I forgot to cite)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!doctype html> | |
<html lang=en> | |
<head> | |
<meta charset=utf-8> | |
<meta name="viewport" content="width=device-width, initial-scale=1"> | |
</head> | |
<body> | |
<script src="./index.js"></script> | |
</body> | |
</html> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var emoji = { | |
cyclone: String.fromCodePoint(0x1f300), | |
check: String.fromCodePoint(0x2705), | |
cross: String.fromCodePoint(0x274c), | |
} | |
const ready = (fn, win = window) => { | |
if (win.readyState !== 'loading') { | |
fn(); | |
} else { | |
win.addEventListener('DOMContentLoaded', fn); | |
} | |
} | |
const spinner = () => `<span class="spinner">${emoji.cyclone}</span>` | |
const render = state => document.body.innerHTML = ` | |
<div> | |
<button | |
onclick="machine.dispatch('click')" | |
${state === 'loading' ? 'disabled' : ''}> | |
Click ${state === 'loading' ? spinner() : ''} | |
</button> | |
${state === 'success' ? emoji.check : ''} | |
</div> | |
` | |
const service = { | |
getData() { | |
// return new Promise((res, rej) => setTimeout(rej, 1000)) | |
return new Promise((res, rej) => setTimeout(res, 1000)) | |
} | |
} | |
const machine = { | |
dispatch(actionName, payload) { | |
// const actions = this.transitions[this.state]; | |
const action = this.transitions[this.state][actionName]; | |
if (action) { | |
console.log('Action dispatched', actionName, payload); | |
action.apply(machine, payload); | |
} | |
}, | |
changeStateTo(newState) { | |
render(newState); | |
this.state = newState; | |
}, | |
state: 'idle', | |
transitions: { | |
'idle': { | |
click() { | |
this.changeStateTo('loading'); | |
service.getData().then( | |
data => { | |
try { | |
this.dispatch('success', data); | |
} catch (error) { | |
this.dispatch('failure', error) | |
} | |
}, | |
error => this.dispatch('failure', error) | |
); | |
} | |
}, | |
'loading': { | |
success(data) { | |
this.changeStateTo('idle'); | |
}, | |
failure(error) { | |
this.changeStateTo('error'); | |
} | |
}, | |
'error': { | |
retry() { | |
this.changeStateTo('idle'); | |
this.dispatch('click'); | |
} | |
} | |
} | |
} | |
ready(() => render(machine.state)); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Live demo on blocks.roadtolarissa.com