有限状态机(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与有限状态机的更多相关文章

  1. javascript实现有限状态机

    1.状态机描述 简单说,有限状态机是一种模型,模型都用来模拟事物,能够被有限状态机这种模型模拟的事物,一般都有以下特点: 1)可以用状态来描述事物,并且任一时刻,事物总是处于一种状态: 2)事物拥有的 ...

  2. React源码剖析系列 - 生命周期的管理艺术

    目前,前端领域中 React 势头正盛,很少能够深入剖析内部实现机制和原理.本系列文章希望通过剖析 React 源码,理解其内部的实现原理,知其然更要知其所以然. 对于 React,其组件生命周期(C ...

  3. FW: javascripts 要不要加引号

    Javascript编程风格  http://www.ruanyifeng.com/blog/2012/04/javascript_programming_style.html 作者: 阮一峰 日期: ...

  4. ☀【JS】有效状态机

    JavaScript与有限状态机http://www.ruanyifeng.com/blog/2013/09/finite-state_machine_for_javascript.html

  5. React 源码剖析系列 - 生命周期的管理艺术

    目前,前端领域中 React 势头正盛,很少能够深入剖析内部实现机制和原理. 本系列文章 希望通过剖析 React 源码,理解其内部的实现原理,知其然更要知其所以然. 对于 React,其组件生命周期 ...

  6. 用于ASP.net的MVC模块

    下载MVCBricks_SRC - 492.58 KB 表的内容 介绍系统要求游戏闪屏的最终考虑历史 介绍 自从我写上一篇关于ASP的文章以来,已经有很长时间了.净的话题.这次我决定写一些关于它的东西 ...

  7. 试试用有限状态机的思路来定义javascript组件

    本文是一篇学习性的文章,学习利用有限状态机的思想来定义javascript组件的方法,欢迎阅读,后续计划会写几篇专门介绍自己利用有限状态机帮助自己编写组件的博客,证明这种思路对于编程实现的价值,目前正 ...

  8. JavaScript有限状态机实现方式

    阮一峰博客 http://www.ruanyifeng.com/blog/2013/09/finite-state_machine_for_javascript.html 开源实现库(javascri ...

  9. JavaScript对象状态

    有限状态机(Finite-state machine)是一个非常有用的模型,可以模拟世界上大部分事物. 简单说,它有三个特征: * 状态总数(state)是有限的. * 任一时刻,只处在一种状态之中. ...

随机推荐

  1. hdu acm 2082 找单词

    找单词 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submiss ...

  2. JS动态级联菜单

    JS动态级联菜单是前端常用的一个功能,特此抽时间研究了下,附上代码 <html> <head> <meta charset="utf-8" /> ...

  3. 结对开发训练(郭林林&胡潇丹)

    此次编程题为:求一个整数数组最大子数组之和,要求时间复杂度为O(n). 首先,我们对题目做出分析,做出第一种预行方案,即定义一个数组,当数组中元素大于等于0时,进行累加:若小于0,则与后面的数作比较, ...

  4. Eclipse不能自动编译 java文件

      在网上的解决方法 方法参考如下: (1) Window-->Preferences-->General-->Workspace  有个"Build automatica ...

  5. phpcms v9 标签含义整理

    {template "content","header"}   ----------  调用根目录下phpcms\template\content\header ...

  6. nodejs安装/运行脚本

    本文主要介绍nodejs在windows下安装及运行脚本. 安装nodejs 先从nodejs官网:http://nodejs.org/下载对应的系统的安装包,比如用于64位系统的最新0.10.21的 ...

  7. C#中使用OpenSSL的公钥加密/私钥解密

    在C#中进行公钥加密/私钥解密,需要用RSACryptoServiceProvider,但是它不支持由OpenSSL生成的公钥/私钥字符串. 比如这样的公钥/私钥对( 公私钥生成方法见 http:// ...

  8. RCP:给GEF编辑器添加网格和标尺。

    网格和标尺效果如上图所示. 添加网格比较简单,也可以自己实现,主要思路是为编辑器添加一个GridLayer.但是还是建议参考eclipse自己的GEF样例来实现. 需要注意两个部分: 1.重写org. ...

  9. java 多线程(wait/notify/notifyall)

    package com.example; public class App { /* wait\notify\notifyAll 都属于object的内置方法 * wait: 持有该对象的线程把该对象 ...

  10. kvm 简介

    1. 基础概念 1.1 kvm整合入linux 内核: 1.2 kvm模型中,每一个虚拟机对于linux而言都是一个标准进程: 1.3 普通的linux进程有用户和内核两个空间,在kvm模型中定义了客 ...