Skip to content

Instantly share code, notes, and snippets.

@whiteinge
Last active July 27, 2023 10:32
Show Gist options
  • Save whiteinge/0c5668ee565df6e9f21aef83f089dd2a to your computer and use it in GitHub Desktop.
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)
<!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>
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));
@whiteinge
Copy link
Author

whiteinge commented Jun 15, 2022

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment