本文经过设计一个简单的任务中心来展现一个使用有限状态机思想设计该如何作。前端
本文使用 JSDOC 添加注释。git
有限状态机 (FSM) 维基 百度百科 是用来表示有限个状态及在这些状态之间转移和动做的数学模型。早在07年就有文章讲解 js 与状态机的结合。github
在程序中,咱们用这种数学模型抽象业务的复杂行为。做为状态机,有如下特征特色:bash
任务中心具备如下功能:架构
若是针对以上需求,整理整个流程, 能够认为任务中心的流程以下:测试
由于需求中存在“能够在任什么时候间塞入任务”,因此对于不一样的流程设定任务的不一样执行状态。ui
分离了任务中心和任务,这两种并行的状态,咱们就能够分开设计,分开编码了。编码
那么先作任务中心组件的实际设计,关于这个组件可能有的状态以下:spa
初始状态设计
运行状态
暂停状态
恢复状态
恢复后的运行状态
中止状态
重启状态
........
但因为咱们组件有的功能,咱们仅为组件设计了四个状态就能够描述其整个生命流程:
由于咱们的这个任务中心是给任务调度用的,因此仅跟任务有关的状态才是有用的状态,这也是状态机设计思惟的核心之一,仅设计使用相关联的状态, 并保证剩余的状态可成为完整的流程, 任务中心的四个状态组成流程以下图所示:
为了更好的展现事务状态,咱们在组件状态切换中加入明确的状态标识。并在类的状态列表定义它们:
/** * 枚举 InstantTask 组件状态 * @enum {Number} * @readonly */
InstantTask.State = Object.freeze({
/** * @memberof InstantTask.State * @type {Number} */
IDLE: 0,
/** * @memberof InstantTask.State * @type {Number} */
RUNNING: 1,
/** * @memberof InstantTask.State * @type {Number} */
PAUSED: 2,
/** * @memberof InstantTask.State * @type {Number} */
STOPPED: 3,
});
复制代码
组件一共存在五个行为, 这些行为在数学中能够被认为是变换器,它们就是上述状态机运转图的具体行为体现。
start()
用于启动组件,设置组件为 RUNNING
状态。
上一个状态能够是任何状态。
用于启动任务中心,并会执行全部以前塞入并无被执行的任务
pause()
用于暂停组件,设置组件为 PAUSED
状态。
上一个状态只能是 RUNNING
状态。
用于暂停任务中心,在暂停后任何任务塞入也不会被执行
resume()
用于恢复组件的暂停状态,设置组件为 RUNNING
状态
上一个状态只能是 PAUSED
状态
用于启动任务中心,并会执行全部以前塞入并无被执行的任务,和start()之间功能差距不大,可是不会像start()同样重置全部设定,并且主要用途是和pause方法作一一对应。一个方法或者状态的多用途对于状态机设计来讲会增长架构复杂度,尽可能避免吧。
stop()
用于中止任务中心,设置组件为 STOPPED
状态
上一个状态只能是 RUNNING
状态
用于中止任务中心,和pause的区别是它会记录中止状态,而且不能被resume,和pause内部逻辑差距不大。主用途是和start()作对立方法。
reset()
用于重置任务中心,设置组件为 IDLE
状态
上一个状态能够是任何状态, 但主要是 STOPPED
状态
用于重置任务中心,此方法等于生成一个新的任务中心。
当咱们肯定组件的抽象运行状态和运行行为后,就能够结合实际业务逻辑来实现具体的组件了。 本文中使用 EventEmitter
来做为事件的广播和处理,前端也能够借用 eventemitter3
这样的近似的类实现一样的功能。
同时接下来本文使用代码中注释的方式继续说明每一个方法的详细用途:
具体代码已经放在: https://gist.github.com/Suixinlei/4b2da4ee1ef84e89b5cfccc1b88b3e4f
测试代码放在: https://gist.github.com/Suixinlei/d8441babe5174b7b1d4326f39b0fcff2
测试结果以下所示,咱们能够看到实际运行结果和咱们的抽象设计彻底一致,充分证实抽象设计对最终逻辑的影响:
添加任务 instant1
添加任务 instant2
任务中心开始运行
instant1 run
instant2 run
添加任务 instant3
instant3 run
任务中心已暂停
添加任务 instant4
恢复运行
instant4 run
复制代码
目前来讲,全部任务都是即时任务,因此对于任务中心的状态仅有四种便可知足需求。若是这些任务有一些是定时任务,甚至能够循环执行并规定执行次数呢?读完这篇文章我想你心中应该已经有些想法, 那么看看下面的最终实现和你想的是否有些出入呢?
这里是最终实现: https://gist.github.com/Suixinlei/e245812799fa160cdf0bbcdf279e68bc
使用 FSM 设计组件能够
关注查看更多原创内容
关注公众号投递简历 (招聘视觉、交互、前端)