【问题标题】:JavaScript Event State MachineJavaScript 事件状态机
【发布时间】:2012-11-07 02:33:14
【问题描述】:

有人知道状态机的任何 javascript 实现吗?我的目标是设置一个将事件绑定到状态转换的状态机实现。因此,如果用户单击按钮,则状态将被更改,并且此状态可能会在要更改的对象中定义某些值。

我希望这是一个状态机,因为会有一个规则 json 文件,允许在调用某些事件时指示各种对象的哪些值发生变化。因为这将在文件中进行结构化,所以我认为将这些信息解析为状态机对象会很容易。

【问题讨论】:

标签: javascript state-machine


【解决方案1】:

js中有两个主要的有限状态机库:

1/Machina: 非常有据可查的示例,支持两个开箱即用的 JavaScript 消息总线提供程序:postal.jsamplify.js

2/Javascript State Machine: 更简单易用,非常适合“基本”用途。

【讨论】:

    【解决方案2】:

    我最近在 JS 中构建了一个状态机实现,这当然是最容易配置的,这要归功于它的转换 DSL:

    transitions: [
      'next    : intro > form > finish',
      'back    : intro < form           < error',
      'error   :         form >           error',
      'restart : intro        < finish'
    ]
    

    它在配置和事件处理程序分配方面都非常灵活,您可以在运行时添加和删除状态、暂停和恢复转换、挂钩大量事件,以及 jQuery 和响应式框架(如 Vue)的帮助器:

    这里有文档和大量演示:

    【讨论】:

    • 状态机的 DSL 看起来确实是一个有趣的想法 ?
    • X-State 可能是当今最流行的状态机。在某些时候,我想重构 DSL 生成器以使用这个或 X-State。但这可能需要一段时间!
    【解决方案3】:

    我的状态机的一点点提升:stateflow 我刚刚创建了自己的状态机,因为我没有找到对我来说足够简单的状态机。

    一个流是用一个js对象定义的,其中属性是状态名称,值是另一个具有以下属性的js对象。

    • 类型:开始、结束或状态(默认)。
    • action:State 实例对象设置为此的函数,也可以命名为先前注册的操作或另一个流定义,在这种情况下它是一个子流。
    • 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 查看它

    【讨论】:

    • 谢谢,关于如何将它添加到 AngularJS 1.x 应用程序中的任何 cmet?
    【解决方案4】:

    尝试查看https://github.com/steelbreeze/state.js - 它支持 UML 2 规范中描述的大部分状态机语义,同时仍然具有高性能。 文档的方式还不是很多,但是示例和测试应该提供很好的参考。

    【讨论】:

    【解决方案5】:

    【讨论】:

      【解决方案6】:

      我对 js-fsm 微型库的选择。

      特点

      • 基于状态的 FSM 描述。由一个和一组状态转换组成的状态。
      • 从事件转换。多个事件定义 ORed 事件。
      • 从条件转换。条件是一个键:应该在条件对象上匹配的值对。多个键、值对定义了 AND 条件。多个条件定义 ORed 条件
      • 每个转换都可以选择调用动作或多个动作。操作可以选择有参数或成为 this 的成员。
      • 状态机可以混合(作为混合)到现有对象或构造函数的原型。为此提供了一种方法。
      • 如果此设备上存在或提供了日志方法,则状态机可以选择性地进行日志记录。
      • 支持 AMD 和 Node 模块。
      • 使用 QUnit 进行单元测试。

      js-fsm github page.

      【讨论】:

        【解决方案7】:

        我想我也会谈谈我自己的状态机库。两年前我遇到了这个 SO 问题,找不到任何符合我要求的东西,所以我写了state-transducer

        API 的主要目标是:

        • 功能性 API,完全没有效果,具有封装的内部状态
        • 通用性和可重用性(没有规定适应特定用例或框架)
        • 必须能够在当前设计之上添加并发和/或通信机制
        • 必须能够顺利集成到 React、Angular 和您的流行框架中

        用于modelize user interfaces,转用户流

        进入状态机

        【讨论】:

          【解决方案8】:

          你可能会发现这个库的使用:

          https://www.npmjs.com/package/mistic

          免责声明:我维护它。

          【讨论】:

            【解决方案9】:

            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' />

            还有一个检查员可以可视化您的机器的工作方式(通过时间旅行),例如:

            【讨论】:

              【解决方案10】:

              我使用过xtstate,它几乎解决了问题中发布的所有问题。它有一个很棒的visualizer 试试看。

              【讨论】:

                猜你喜欢
                • 2016-01-16
                • 2011-10-10
                • 1970-01-01
                • 2010-09-24
                • 1970-01-01
                • 2012-10-29
                • 1970-01-01
                • 1970-01-01
                • 2021-12-15
                相关资源
                最近更新 更多