• QQ空间
  • 收藏

JavaScript与有限状态机

| 2020-03-22

有限状态机(Finite-state machine)是一个非常有用的模型,可以模拟世界上大部分事物。

简单说,它有三个特征:

  * 状态总数(state)是有限的。
  * 任一时刻,⿺只处在一种状态之中。
  * 某种条件下,会从一种状态转变(transition)到另一种状态。

它对JavaScript的意义在于,很多对象可以写成有限状态机。

举例来说,网页上有一个菜单元素。鼠标悬停的时候,菜单显示;鼠标移开的时候,菜单隐藏。如果使用有限状态机描述,就是这个菜单⊙只有两种状态(显示和隐藏),鼠标会引发状态转变。

代码可以写成下面这样:

  var menu = {        // 当前状态     currentState: 'hide',        // 绑定事件     initialize: func◤tion() {       var self = thщis;   ▊    self.on∮("hover", self.transition);     },        // 状态转换     transition: function(event){       switch(this.currentState) {   Ⅹ    $  case "hide":           this.currentState = 'show';           doSomething();           break;         case "show":         ↈ  this.currentState = 'h●·ide';           doSomething();           break;         default:           console.log('Invиalid Sё-tate!');           break;       }     }      };   

可以看到,有限状态机的写法,逻辑清晰,表达力强,有利于封装事件。一个对象的状态越多、发生的事件越多,就越适合采用有限状态机的写法。

另外,JavaScript语言是一种异步操作特别多的语言,常用的解决方法是指定回调函数,但这样会造成代码结构混乱、难以测试和除错等问题。有限状态机提供了更好的办法:把异步操作与对象的状态改变挂钩,当异步操作结束的时候,发生相应的状态改变,由此再触发其他操作。这要比回调函数、事件监听、发布/订阅等解决方案°゜,在逻辑上更合理,更易于降低代码的复杂度。

下面介绍一个有限状态机的函数库Javascript Finite State MaЭchine。这个库非常好懂,可以í帮助我们加深理解,而且功能一点都不弱。

该库提供一个全局对象StateMachine,使用该对象的create方法,可以生成有限状态机的实例。

┈┉  var fsm = S◈tateMachineσ.create();   

生成的时候,需要Б提供一个参数对象,用来描述实例的性质。比如,交通信号灯(红绿灯)可以这样描述:

  var fsm = StateMachine.create({        i∝nitial: 'green',        events: [       { name: 'warn', from: 'green', to: 'yellow' },       { name: 'stop', from: 'yellow', to: 'red' },       { name: 'r☞eady', from: 'red', to: 'yellow' },   ⊿    { name: 'go', ┎from: 'yellow', to: 'gr►een' }     ]      });   

交通信号灯的初始状态(initial)为green,events属性是触发状态改变的各种事件,比如warn事件使得green状态变成yellow状态,stop事件使得yellow状态变成red状态等等。

生成实例以后,就可以随时查询当前状态。

* fsm.current :返回当前状态。
* fsm.is(s) :返回一个≤布尔值,表示状态s是否为当前状态。
* fsm.can(e) :返回一个布尔值,表示事件e是否能在当前状态触发。
* fsm.cannot(e) :返回一个布尔值,表示事件e是否不能在当前状态触发。

Javascript Finite State Machine允许为每个事件指定两个回调函数,以warn事件为例:

* onbef※orewarn:在warn事件发生之前触发。
* onafterwarn(可简写成onwarn) :在warn事件发生之后触发。

同时,它也ψ允许为每个状态指定两个回调函数,以green状态为例:

* on◤leavegreen :在⊙离开green状态时触发。
* onentergreen(可简写成ongreen) :在进入green状态时触发。

假定warn事件使得状态从green变为yellow,上面四类回调函数的发生顺序如下:┚onbeforewarn → onle≠avegreen → onenteryellow → onafterwarn。

除了为每个事件和状态单独指定回调函数,还可以为所有的事件和状态指定通用的回调〓函数。

* onbeforeevent :任一事件发生之前触发。
* onleavestate :离开任一状态时触发。
* onenterstate :┑进入任一状态时触发。
* onafterevent :任一事件结束后触发。

如果事件的回调函数里面有异步操作(比如与服务器进行Ajax通信),这时我们可能希望∈等到异︶︷︸步操作结束,再发生状态″改变。这就要用到transi⿷tion方法。

∽   fsm.onleavegreen = function(){     ligh↗t.fadeOut('slow', function(ч) {       fsm.transition();     });     return StateMachine.ASYNC;   };   

上面代码的回调函数里面,有一个异步操作(light.fadeOut)。如果不希望状态立即改变,就要让回调函数返回StateMachine.ASYNC,表示状态暂时不改变;等到异步操作结束′,再调用transition方法,使得状态发生┘改@变。

Javascript Finite State Machine还允许指定错误处理函数,当发生了当前状态不可能▣▤▥发生的事件时自动触发。

  var fsm = StateMachine.create({     // ...     error: ⿻function(eventName, from, to, args, errorCode¤, errorMessage)Ⅳ {       return 'event ' + ev▂▃▅▆█entNameю + ': ' + errorMessage;     },     // ...   });   

比如,当前状态是green,理论上这时只可能发生warn事件。要是这时发生了stop事件,就会触发上面的错误处理函数。

Javascript Finite State Machine的基本用法就Ⅻ是上面这些,更详细的介绍可以参见它的主页。

(完)

2020-03-22
百家号 undefined与null的区别
大多数计算机语言,有且仅有一个表示"无"的值,比如,C语言的NULL,Java语言的null,Python语言的None,Ruby语言的nil。 ... <详情>
2020-03-22
百家号 JavaScript与有限状态机
有限状态机(Finite-state machine)是一个非常有用的模型,可以模拟世界上大部分事物。 ... <详情>
2020-03-22
百家号 标签体系应用及设计思路
在标签画像建设之上,更加具体的应用目的是什么呢? 本文将为你重点介绍: 企业做标签画像的目的; 标签和画像的应用场景及应用流程; 构建标签和画像体系的实操方... <详情>
2020-03-22
百家号 谈谈我运营小说站群月入7000元的一些经验
大家好,我是4K。好久好久没写东西分享了,记得上一次写东西大概是两年前了,那时木耳还是蔬菜,葡萄还是水果,而今神马都变了,青葱的岁月啊……(此处省略10000个... <详情>
2020-02-29
百家号 Red Tape X:2015年最佳音乐营销手段
音乐营销公司Red Tape X总结了2015年最佳音乐营销手段,以及这些手段是怎样被最当红且最具创新力的大明星们高效利用的。 2015年对于音乐来说是难熬的,... <详情>
2020-02-29
百家号 做seo要注意哪些技巧
  在搜索引擎优化原创当道的当下,还写伪原创办法如同有点不大适宜,不过谁让咱是搜索引擎优化呢,谁让咱不是对切职业都了解呢!别的伪原创也需求剖析访客需求,不能解决... <详情>