JavaScript Event State Machine
Кто-нибудь знает какие-либо реализации javascript конечного автомата? Моя цель - настроить реализацию конечного автомата, которая бы связывала события с переходами состояний. Таким образом, если пользователь нажимает кнопку, то состояние будет изменено, и это состояние может определять, например, определенные значения в объектах, которые необходимо изменить.
Я хочу, чтобы это был конечный автомат просто потому, что будет файл json правил, который позволит определять, какие значения изменяются для различных объектов при вызове определенных событий. Поскольку это будет структурировано в файле, я думаю, что было бы легко проанализировать эту информацию в объекте конечного автомата.
8 ответов
В js есть две основные библиотеки для конечного автомата:
1 / https://github.com/ifandelse/machina.js Очень хорошо документированные примеры, в которых поддерживается два поставщика шины сообщений JavaScript: postal.js и ampify.js.
2 / https://github.com/jakesgordon/javascript-state-machine проще и удобнее в использовании, идеально подходит для "базового" использования.
Недавно я создал реализацию конечного автомата в JS, которую, безусловно, проще всего настроить благодаря переходному DSL:
transitions: [
'next : intro > form > finish',
'back : intro < form < error',
'error : form > error',
'restart : intro < finish'
]
Он действительно гибок как в настройке, так и в назначении обработчика событий, вы можете добавлять и удалять состояния во время выполнения, приостанавливать и возобновлять переходы, подключаться к куче событий, с помощью помощников для jQuery и реактивных сред, таких как Vue:
Документы и целый ряд демонстраций здесь:
Немного рекламы моего конечного автомата: stateflow Я просто создал собственный конечный автомат, потому что не нашел ничего, что было бы достаточно просто для меня.
поток определяется с помощью объекта js, где свойством является имя состояния, а значением является другой объект js со следующими свойствами.
- Тип: начало, конец или состояние (по умолчанию).
- action: function с объектом экземпляра State, установленным в this, также может называться action ранее зарегистрированным или другим определением потока, в этом случае это подпоток.
- on: свойство должно соответствовать событию, а значение - следующее состояние для перехода
Простой пример
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);
});
Проверьте это на git https://github.com/philipdev/stateflow или через npm
Попробуйте взглянуть на https://github.com/steelbreeze/state.js - он поддерживает большую часть семантики конечного автомата, как описано в спецификации UML 2, но при этом сохраняет производительность. Документации пока немного, но примеры и тесты должны послужить хорошим справочным материалом.
Вы найдете библиотеку, разработанную с помощью jQuery, которая, кажется, выполняет то, что вы ищете, и автоматически связывает события для вас:
Я могу выбрать это с помощью микро-библиотеки JS-FSM.
Характеристики
- Описание штата FSM. Состояние, состоящее из a и массива переходов состояний.
- Переход от событий. Несколько событий определяют события ORed.
- Переход от условий. Условие - это пара ключ: значение, которое должно соответствовать объекту условия. Несколько ключей, пар значений определяют условия ANDed. Несколько условий определяют условия ORed
- Каждый переход может опционально вызывать действия или несколько действий. Действия могут иметь аргументы или быть участниками этого.
- Конечный автомат может быть смешан (как mixin) с существующим объектом или прототипом конструктора. Метод для этого предоставляется.
- Конечный автомат может при желании регистрировать, если метод регистрации существует на этом или предоставляется.
- Поддерживаются модули AMD и Node.
- Модульные тесты с QUnit.
Я думал, что я также буду говорить о моей собственной библиотеке конечного автомата. Я пришел к этому такому вопросу два года назад и не смог найти ничего, что соответствовало бы моим требованиям, поэтому я написал state-transducer.
Основными задачами для API было:
- функциональный API, полностью лишенный эффекта, с инкапсулированным внутренним состоянием
- универсальность и возможность повторного использования (не предусмотрено положение, учитывающее конкретные случаи использования или структуры)
- должна быть возможность добавить механизм параллелизма и / или связи поверх текущего проекта
- должна быть возможность плавно интегрироваться в React, Angular и ваши популярные фреймворки
Он используется для моделирования пользовательских интерфейсов, превращения пользовательских потоков
в конечные автоматы
Я использовал xtstate, он решает почти все проблемы, указанные в вопросе. У него отличный визуализатор, попробуйте.
Вы можете найти эту библиотеку использования:
https://www.npmjs.com/package/mistic
Отказ от ответственности: я поддерживаю это.
Новая библиотека: https://github.com/jml6m/fas-js - простая и удобная в использовании
В README также есть демо.
AsyncMachine - это другой, менее ортодоксальный подход к государственной машине в JS (я автор). Он реляционный и поддерживает одновременную активность нескольких состояний. Вот некоторый код для ответа на исходный вопрос - после нажатия кнопки появляются побочные эффекты с точки зрения нового состояния и атрибута для объекта контекста:
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' />
Также есть инспектор, который может визуализировать работу вашей машины (с путешествиями во времени), например: