专栏首页阮一峰的网络日志JavaScript与有限状态机

JavaScript与有限状态机

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

简单说,它有三个特征:

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

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

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

代码可以写成下面这样:

  var menu = {            // 当前状态     currentState: 'hide',        // 绑定事件     initialize: function() {       var self = this;       self.on("hover", self.transition);     },        // 状态转换     transition: function(event){       switch(this.currentState) {         case "hide":           this.currentState = 'show';           doSomething();           break;         case "show":           this.currentState = 'hide';           doSomething();           break;         default:           console.log('Invalid State!');           break;       }     }      };

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

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

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

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

  var fsm = StateMachine.create();

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

  var fsm = StateMachine.create({        initial: 'green',        events: [       { name: 'warn', from: 'green', to: 'yellow' },       { name: 'stop', from: 'yellow', to: 'red' },       { name: 'ready', from: 'red', to: 'yellow' },       { name: 'go', from: 'yellow', to: 'green' }     ]      });

交通信号灯的初始状态(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事件为例:

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

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

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

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

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

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

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

  fsm.onleavegreen = function(){     light.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 ' + eventName + ': ' + errorMessage;     },     // ...   });

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

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

(完)

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 关于2的补码

    问一个基本的问题。 负数在计算机中如何表示? 举例来说,+8在计算机中表示为二进制的1000,那么-8怎么表示呢? 很容易想到,可以将一个二进制位(bit)专门...

    ruanyf
  • Stack的三种含义

    学习编程的时候,经常会看到stack这个词,它的中文名字叫做"栈"。 理解这个概念,对于理解程序的运行至关重要。容易混淆的是,这个词其实有三种含义,适用于不同的...

    ruanyf
  • Node.js 命令行程序开发教程

    一种编程语言是否易用,很大程度上,取决于开发命令行程序的能力。 Node.js 作为目前最热门的开发工具之一,怎样使用它开发命令行程序,是 Web 开发者应该掌...

    ruanyf
  • 微信小程序实战开发二:微信小程序 WEUL组件之 画廊组件

    官方地址:https://developers.weixin.qq.com/miniprogram/dev/extended/weui/gallery.html

    睿儿网络郝刚
  • SAP S4HANA里关于生产订单的一些重要数据库表

    版权声明:本文为博主汪子熙原创文章,未经博主允许不得转载。 https://jerry.bl...

    Jerry Wang
  • 《纽约时报》如何打造新一代推荐系统

    用户1737318
  • 看《纽约时报》如何用数据算法打造新一代推荐系统!

    通过精炼读者获取这些内容的途径,即在移动应用和网站上基于读者喜好调整文章布局,能够帮助读者找到与他们相关的内容,比如在正确的时间推送读者感兴趣的内容、重大事件的...

    华章科技
  • 『互联网架构』软件架构-解密电商系统-互联网BAT商品详情缓存架构(82)

    PS:通过看的技术文章,在详细的看看这本书,其实互联网技术不过如此,自古真情留不住,唯有套路的人心,都是前人总结的解决问题的方案和套路,对于有互联网经验这本书还...

    IT故事会
  • 1074 食物链 2001年NOI全国竞赛

    1074 食物链 2001年NOI全国竞赛 时间限制: 3 s 空间限制: 64000 KB 题目等级 : 钻石 Diamond 题目描述 Des...

    attack
  • SAP 跨工厂生产功能演示

    多工厂的生产组织形式下,如果有一个中央计划工厂,统一负责成品的对外销售发货等,而具体的生产作业分别由不同的工厂执行,那么可以采用特殊采购类型进行计划的传递。

    用户5495712

扫码关注云+社区

领取腾讯云代金券