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.

js-fsm github page.

Я думал, что я также буду говорить о моей собственной библиотеке конечного автомата. Я пришел к этому такому вопросу два года назад и не смог найти ничего, что соответствовало бы моим требованиям, поэтому я написал state-transducer.

Основными задачами для API было:

  • функциональный API, полностью лишенный эффекта, с инкапсулированным внутренним состоянием
  • универсальность и возможность повторного использования (не предусмотрено положение, учитывающее конкретные случаи использования или структуры)
  • должна быть возможность добавить механизм параллелизма и / или связи поверх текущего проекта
  • должна быть возможность плавно интегрироваться в React, Angular и ваши популярные фреймворки

Он используется для моделирования пользовательских интерфейсов, превращения пользовательских потоков

пользовательский поток

в конечные автоматы

FSM

Я использовал 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' />

Также есть инспектор, который может визуализировать работу вашей машины (с путешествиями во времени), например:

Другие вопросы по тегам