JavaScript finite state machine

  sonic0002        2013-09-02 11:00:57       11,993        0    

Finite state machine is a very useful design model, it can be used to simulate many events in the world.

In short, finite state machine has three features:

  • Number of states is finite
  • At any moment, one object can only be in one state
  • In some condition, it will transfer from one state to another state

In JavaScript, finite state machine can be applied in many places. For example, one menu element on a webpage. When the mouse hovers on the menu, the menu will show up, while the mouse moves away, the menu will hide. If we use a state machine, there are two states(show and hide), the mouse will trigger the state transition.

The code can be written as :

 var menu = {
      
    // Current state
    currentState: 'hide',
  
    // Bind events
    initialize: function() {
      var self = this;
      self.on("hover", self.transition);
    },
  
    // State 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;
      }
    }
  
  };

We can see that a state machine has a clear logic and it's expressive. It is also useful for encapsulating events. If one object has many states and it may trigger many events, then state machine is an excellent candidate.

In addition, JavaScript has many asynchronous operations, the common solution is to specify callbacks, but this will introduce a bad code structure. Finite state machine provides a better solution, it kooks up the asynchronous operation with object states. When asynchronous operations are completed, respective states will be changed as well, then other events will be triggered.

Next we will introduce a finite state machine library JavaScript Finite State Machine. This library is easy to understand, it can help us strengthen our understanding about our codes.

This library provides a StateMachine object, we can create instance of the state machine with the create() method.

var fsm = StateMachine.create();

When calling this method, we need to provide an option object to describe the instance. For example, the traffic light can be described as:

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' }
    ]
  
});

The traffic light has an initial state green, events contains the events which trigger the state transition, for example warn event transfers green state to yellow state, stop event transfers yellow state to red state etc.

When the instance is created, we can check the current status:

  • fsm.current -- Return current state
  • fsm.is(s) -- return a boolean value to indicate whether s is the current state
  • fsm.can(e) -- Return aboolean value to indicate whether e can be trigger in current state
  • fsm.cannot(e) -- return a boolean value to indicate whether e cannot be triggered in current state

JavaScript finite state machine allows each event to have two callbacks. Take warn event as an example:

  • onbeforewarn -- Trigger before warn event
  • onafterwarn -- Trigger after warn event

At the same time, it allows each state to have two callback as well. Take state green as example:

  • onleavegreen -- Trigger when leaving green state
  • onentergreen -- Trigger when entering state green

Assume the warn event transfers the state from green to yellow. The above 4 callbacks will be called in the order : onbeforewarn->onleavegreen->onenteryellow->onafterwarn.

In addition to specify callback for each event and state independently, we can specify common callbacks for event and state.

  • onbeforeevent -- Trigger before any event
  • onleavestate -- Trigger when leaving any state
  • onenterstate -- Trigger when entering any event
  • onafterevent -- Trigger when any event finishes

If there are asynchronous operations in callbacks(such as AJAX), then we may need to wait for the completion of asynchronous operations before the state transition. Now we need to use transition method.

fsm.onleavegreen = function(){
    light.fadeOut('slow', function() {
      fsm.transition();
    });
    return StateMachine.ASYNC;
};
  

JavaScript finite state machine also allows to specify error handling functions.

var fsm = StateMachine.create({
    // ...
    error: function(eventName, from, to, args, errorCode, errorMessage) {
      return 'event ' + eventName + ': ' + errorMessage;
    },
    // ... 
});

If the current state is green, in theory only warn event can happen now, if stop event happens, then it will trigger the error handling function.

For more details about JavaScript finite state machine. Please check here

Author : é˜®ä¸€å³° Source : http://www.ruanyifeng.com/blog/2013/09/finite-state_machine_for_javascript.html

JAVASCRIPT  FINITE STATE MACHINE  STATE 

       

  RELATED


  0 COMMENT


No comment for this article.



  RANDOM FUN

I am not a robot