一个简单的有限状态机(easy-fsm)

最近一个前端项目中,我需要用有限状态机对代码逻辑进行管理。一开始想用 javascript-state-machine 这个库,后来注意到如果商用,它需要购买商业授权。然后又研究了一下 xstate,它的功能很完备,并且项目很活跃,但在研究了一番之后,发现它体积有一点大,压缩过之后也有 20K 以上。鉴于我的需求相对简单,同时对代码的体积有一定要求,于是便重新造了一个轮子:easy-fsm

有限状态机(FSM,Finite State Machines)是表示有限个状态以及在这些状态之间的转移和动作等行为的数学模型,具体定义可看维基百科。GitHub 上有很多有限状态机的框架或者库,easy-fsm的特点是小巧精简,只保留最常用的核心功能,支持async/await,同时有完善的测试用例。

开关按钮组件可以视为有限状态机的一个极简单的例子。如下图,开关按钮的初始状态为off,可以通过turn_on操作转换到on状态,然后又可以通过turn_off操作回到off状态。

这个组件如果使用easy-fsm版有限状态机来描述,可以写成这样:

const fsm = require('easy-fsm')

let machine = fsm.create({
  initial: 'off', // 初始状态
  states: { // 所有状态列表
    off: { // off 状态
      on: { // 事件
        turn_on: 'on' // 当 turn_on 事件触发时,转换为 on 状态
      }
    },
    on: { // on 状态
      on: { // 事件
        turn_off: 'off' // 当 turn_off 事件触发时,转换为 off 状态
      }
    }
  }
})

然后,可以注册一些事件,比如:

machine.onEnterOff = () => console.log('enter state: off')
machine.onOff = () => console.log('on state: off')
machine.onLeaveOff = () => console.log('leave state: off')
machine.onEnterOn = () => console.log('enter state: on')
machine.onOn = () => console.log('on state: on')
machine.onLeaveOn = () => console.log('leave state: on')

每一个状态state,都有对应的onEnterStateonStateonLeaveState勾子,可以在上面挂载处理函数,当进入、切换到、离开某个状态时,会依次调用对应的处理函数。注意此处的命名方式会转为驼峰式命名,比如如果你的状态是loading_some_files,对应的勾子将是onEnterLoadingSomeFilesonLoadingSomeFiles以及onLeaveLoadingSomeFiles

接着,可以用.fire(event)方法触发事件,从而实现状态间的转换,如:

await machine.fire('turn_on') // 从 off 状态转为 on 状态
await machine.fire('turn_off') // 从 on 状态转为 off 状态

由于之前注册了状态转换时的处理函数,执行上面两条命令,将会在控制台看见如下输出:

leave state: off
enter state: on
on state: on
leave state: on
enter state: off
on state: off

除了.fire(event)方法外,easy-fsm还内置了几个常用方法,分别为:

  • .canFire(event) 判断当前状态下是否可触发指定事件event
  • .getState() 获取当前状态
  • .getLastState() 获取上一个状态,如果当前状态可能有多种进入方式,这个方法可能会很有用

以上就是easy-fsm的主要用法。如果你的项目需要使用有限状态机,并且场景并不是特别复杂,也许可以尝试一下easy-fsmhttps://github.com/oldj/easy-fsm)。

Advertisements

发表评论

Fill in your details below or click an icon to log in:

WordPress.com 徽标

You are commenting using your WordPress.com account. Log Out /  更改 )

Google+ photo

You are commenting using your Google+ account. Log Out /  更改 )

Twitter picture

You are commenting using your Twitter account. Log Out /  更改 )

Facebook photo

You are commenting using your Facebook account. Log Out /  更改 )

Connecting to %s