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的基本用法就是上面这些,更详细的介绍可以参见它的主页。
(完)
源:http://www.ruanyifeng.com/blog/2013/09/finite-state_machine_for_javascript.html
JavaScript与有限状态机的更多相关文章
- javascript实现有限状态机
1.状态机描述 简单说,有限状态机是一种模型,模型都用来模拟事物,能够被有限状态机这种模型模拟的事物,一般都有以下特点: 1)可以用状态来描述事物,并且任一时刻,事物总是处于一种状态: 2)事物拥有的 ...
- React源码剖析系列 - 生命周期的管理艺术
目前,前端领域中 React 势头正盛,很少能够深入剖析内部实现机制和原理.本系列文章希望通过剖析 React 源码,理解其内部的实现原理,知其然更要知其所以然. 对于 React,其组件生命周期(C ...
- FW: javascripts 要不要加引号
Javascript编程风格 http://www.ruanyifeng.com/blog/2012/04/javascript_programming_style.html 作者: 阮一峰 日期: ...
- ☀【JS】有效状态机
JavaScript与有限状态机http://www.ruanyifeng.com/blog/2013/09/finite-state_machine_for_javascript.html
- React 源码剖析系列 - 生命周期的管理艺术
目前,前端领域中 React 势头正盛,很少能够深入剖析内部实现机制和原理. 本系列文章 希望通过剖析 React 源码,理解其内部的实现原理,知其然更要知其所以然. 对于 React,其组件生命周期 ...
- 用于ASP.net的MVC模块
下载MVCBricks_SRC - 492.58 KB 表的内容 介绍系统要求游戏闪屏的最终考虑历史 介绍 自从我写上一篇关于ASP的文章以来,已经有很长时间了.净的话题.这次我决定写一些关于它的东西 ...
- 试试用有限状态机的思路来定义javascript组件
本文是一篇学习性的文章,学习利用有限状态机的思想来定义javascript组件的方法,欢迎阅读,后续计划会写几篇专门介绍自己利用有限状态机帮助自己编写组件的博客,证明这种思路对于编程实现的价值,目前正 ...
- JavaScript有限状态机实现方式
阮一峰博客 http://www.ruanyifeng.com/blog/2013/09/finite-state_machine_for_javascript.html 开源实现库(javascri ...
- JavaScript对象状态
有限状态机(Finite-state machine)是一个非常有用的模型,可以模拟世界上大部分事物. 简单说,它有三个特征: * 状态总数(state)是有限的. * 任一时刻,只处在一种状态之中. ...
随机推荐
- LIS最长上升子序列O(n^2)与O(nlogn)的算法
动态规划 最长上升子序列问题(LIS).给定n个整数,按从左到右的顺序选出尽量多的整数,组成一个上升子序列(子序列可以理解为:删除0个或多个数,其他数的顺序不变).例如序列1, 6, 2, 3, 7, ...
- vs2010中的MSBuild输出warning MSB8012问题
vs2010中,MSBuild与C++编译器无缝整合.无论使用vs2010生成的代码,还是转换vs2008或者是更低版本vs编译的C++代码.都会在工程编译后,都会提示一条错误: C:\Program ...
- Jquery的multifile使用随记
1.多文件上传: 2.如上几个验证不重复,和限制上传数量的验证显示的是英文,改成中文文本时,如果不用国标解码,到时候提示框会出现乱码现象.所以一般需要中文显示的时候,我们应该这样做: 拿denied做 ...
- 【整理】--【KERNEL】内核定时器
一.LINUX内核定时器是内核用来控制在未来某个时间点(基于jiffies)调度执行某个函数的一种机制,其实现位于 <linux/timer.h> 和 kernel/timer.c 文件中 ...
- Android Meun 用法
Android Meun 用法 点击菜单实体键弹出菜单:如下图 main_activity.xml <?xml version="1.0" encoding="ut ...
- CentOs 7怎么联网
在安装好Centos7后,网络还不能正常使用,需要我们手动配置.并且Linux的网络配置并不太容易,新手经常不知道从何开始.为了解决这个令大家头疼的问题,我在此将成功的配置过程与大家分享.希望大家都能 ...
- RCP: MANIFEST.MF, plugin.xml, build.properties三种文件的区别
在Eclipse插件开发中, MANIFEST.MF, plugin.xml, build.properties是三种最常见的文件,由于它们共享同一个编辑器(Plug-in Manifest Edit ...
- 公共代码参考(httpclient)
public class HttpClientUtils { private static final String CHARSET = "UTF-8"; /* * http ge ...
- Alpha阶段冲刺总结
Alpha阶段冲刺阶段总结 预期计划: 本阶段的预期计划是实现打地鼠游戏的基本功能,包括:游戏功能.难度调节功能.计时功能.计数记分功能.DIY设置功能.分数记录功能. 实际进展: 在经过三周的Alp ...
- chrome浏览器渲染白屏问题剖析
刚截图十几次,终于捕捉到了这个白屏现象,hiahia~~ 大家可以很清晰地看到下边还木有渲染完毕的透明层,这是一个十分普遍的问题,经常遇到.我的浏览器版本是 到目前为止应该是最新版(release版本 ...