JavaScript与有限状态机_最新动态_新闻资讯_程序员俱乐部

中国优秀的程序员网站程序员频道CXYCLUB技术地图
热搜:
更多>>
 
您所在的位置: 程序员俱乐部 > 新闻资讯 > 最新动态 > JavaScript与有限状态机

JavaScript与有限状态机

 2013/9/2 17:33:52    程序员俱乐部  我要评论(0)
  • 摘要:有限状态机(Finite-statemachine)是一个非常有用的模型,可以模拟世界上大部分事物。简单说,它有三个特征:*状态总数(state)是有限的。*任一时刻,只处在一种状态之中。*某种条件下,会从一种状态转变(transition)到另一种状态。它对JavaScript的意义在于,很多对象可以写成有限状态机。举例来说,网页上有一个菜单元素。鼠标悬停的时候,菜单显示;鼠标移开的时候,菜单隐藏。如果使用有限状态机描述,就是这个菜单只有两种状态(显示和隐藏),鼠标会引发状态转变
  • 标签:Java 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.onwarn = 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 的基本用法就是上面这些,更详细的介绍可以参见它的主页。

发表评论
用户名: 匿名