javascript实现有限状态机
1、状态机描述
简单说,有限状态机是一种模型,模型都用来模拟事物,能够被有限状态机这种模型模拟的事物,一般都有以下特点:
1)可以用状态来描述事物,并且任一时刻,事物总是处于一种状态;
2)事物拥有的状态总数是有限的;
3)通过触发事物的某些行为,可以导致事物从一种状态过渡到另一种状态;
4)事物状态变化是有规则的,A状态可以变换到B,B可以变换到C,A却不一定能变换到C;
5)同一种行为,可以将事物从多种状态变成同种状态,但是不能从同种状态变成多种状态。
2、思考实现
参照已有的实现功能 https://github.com/jakesgordon/javascript-state-machine/
实现思路
1、单个页面会有多个UI,每个UI可拥有独立的一个状态机,因此用工厂模式的思路实现
2、状态切换间应该有多个时机传回调函数:onbefore->onleave->on[Event]->on[state]->onenter[State]->onafter[event]
3、留个外部调用的一些方法接口is(判断当前状态是不是此state);can(判断状态十分能转换);cannot;transitions(能转换的状态);
代码如下
var sm = (function () {
function _StateMachine(config) {
this.state = config.initial||'unknow';
this.events = config.events;
this.callbacks = config.callbacks||{};
this.error = config.error || function(name, from, to, args, error, msg, e) { throw e || msg; };
this._hashEvent = {}
this.init();
}
var __PREFIX = ['onbefore','onleave','onenter','onafter'];
_StateMachine.prototype.SYNC = 'sync';
_StateMachine.prototype.init = function () {
this._initHashEvent();
this._buildEvent();
}
_StateMachine.prototype._initHashEvent = function () {
for (var i = this.events.length - 1; i >= 0; i--) {
var e = this.events[i];
if (!this._hashEvent[e.name]) {
this._hashEvent[e.name] = []
}
this._hashEvent[e.name].push({
from:e.from,
to:e.to,
name:e.name
})
}
}
_StateMachine.prototype._buildEvent = function () {
var self = this;
for(var i in this._hashEvent){
this[i] = (function (i) {
return function (arg) {
var event = this._getEvent(this._hashEvent[i]);
if (JSON.stringify(event) == '{}') {
return false;
}
this.cacheEvent = event; //用于异步调用
var fn = event.name;
this.callbacks['onbefore'+fn]&&this.callbacks['onbefore'+fn](this,event.name,this.state,event.state,arg);
if(this.callbacks['onbefore'+fn]){
var beforeValue = this.callbacks['onbefore'+fn](this,event.name,this.state,event.state,arg);
}
if(beforeValue == false){
return false;
}
if(this.callbacks['onleave'+this.state]){
var leaveValue = this.callbacks['onleave'+this.state](this,event.name,this.state,event.state,arg);
}
if(leaveValue == false){
console.log('not transform')
return false;
}
if(leaveValue == this.SYNC){
return false;
}
this._transition(arg);
}
})(i);
}
}
_StateMachine.prototype._getEvent = function(hash){
var event={};
for (var i = hash.length - 1; i >= 0; i--) {
var formType = Object.prototype.toString.call(hash[i].from);
if(formType == '[object Array]'){
if(hash[i].from.indexOf(this.state)>=0){
event = hash[i];
break;
}
}else{
if(hash[i].from == this.state){
event = hash[i];
break;
}
}
}
return event;
}
_StateMachine.prototype._transition = function (args) {
var event = this.cacheEvent;
var fn = event.name;
this.prevState = this.state;
this.state = event.to;
this.callbacks['on'+event.name]&&this.callbacks['on'+event.name](this,this.prevState,this.state,args);
this.callbacks['on'+this.state]&&this.callbacks['on'+this.state](this,this.prevState,this.state,args);
this.callbacks['onenter'+this.state]&&this.callbacks['onenter'+this.state](this,event.name,this.prevState,event.state,args);
this.callbacks['onafter'+fn]&&this.callbacks['onafter'+fn](this,event.name,this.prevState,event.state,args);
console.log('sm state transform '+ this.prevState+ ' to '+ this.state);
}
_StateMachine.prototype.is = function (state) {
return this.state == state;
}
_StateMachine.prototype.can = function (eventName) {
var event = this._getEvent(this._hashEvent[eventName]);
return JSON.stringify(event) != '{}';
}
_StateMachine.prototype.cannot = function (eventName) {
var event = this._getEvent(this._hashEvent[eventName]);
return JSON.stringify(event) == '{}';
}
//以数组的形式返回实例当前状态下能够被触发的行为列表
_StateMachine.prototype.transitions = function () {
var events = [];
for (var e in this._hashEvent) {
if(this.can(e)){
events.push(e);
}
}
return events;
}
return {
create:function (config) {
return new _StateMachine(config)
}
}
})();
调用
var fsm2 = sm.create({
initial: 'hungry',
events: [
{ name: 'eat', from: 'hungry', to: 'satisfied' },
{ name: 'eat', from: 'satisfied',to: 'full' },
{ name: 'eat', from: 'full',to: 'sick' },
{ name: 'rest', from: ['hungry', 'satisfied', 'full', 'sick'], to: 'hungry' },
]
});
var fsm = sm.create({
initial: 'green',
events: [
{ name: 'warn', from: 'green', to: 'yellow' },
{ name: 'panic', from: 'yellow', to: 'red' },
{ name: 'calm', from: 'red', to: 'yellow' },
{ name: 'clear', from: 'yellow', to: 'green' }
],
callbacks: {
onpanic: function(event, from, to, msg) { alert('panic! ' + msg); },
onwarn: function(event, from, to, msg) { alert('warn! ' + msg); },
onclear: function(event, from, to, msg) { alert('thanks to ' + msg); },
ongreen: function(event, from, to) { document.body.className = 'green'; },
onyellow: function(event, from, to) { document.body.className = 'yellow'; },
onred: function(event, from, to) { document.body.className = 'red'; },
}
});
javascript实现有限状态机的更多相关文章
- JavaScript与有限状态机
有限状态机(Finite-state machine)是一个非常有用的模型,可以模拟世界上大部分事物. 简单说,它有三个特征: * 状态总数(state)是有限的. * 任一时刻,只处在一种状态之中. ...
- 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)是有限的. * 任一时刻,只处在一种状态之中. ...
随机推荐
- APS期刊投稿准备: REVTex格式
APS是American Physics Society的简称.旗下比较有影响力的期刊有: "pra, prb, prc, prd, pre, prl, prstab, prstper, o ...
- 【Android】带进度条的WebView
http://www.cnblogs.com/over140/archive/2013/03/07/2947721.html
- 理解JAVA内存模型
实际上java内存模型是如上图所示一样 每个线程有自己的栈内存,存放共享对象的副本,本地变量 每个线程自己的本地变量是不可见的,但是共享对象对每个线程都是可见的. 如果想实现线程通信的话, 线程对共享 ...
- IO流回顾与总结第一篇之字节流与字符流的操作。。。。。
一.引言 趁着年后的这点时间,抓紧点时间回顾下javase中的IO流,以往都是用到那些常用的IO类,这次来个全点的,有不对的地方还请大神指正一下,做到坚持写博的习惯来...... 回归正题,IO流顾名 ...
- IntelliJIDEA中如何使用JavaDoc
IntelliJ IDEA 12.1.6,本身提供了很好的 JavaDoc 生成功能,以及标准 JavaDoc 注释转换功能,其实质是在代码编写过程中,按照标准 JavaDoc 的注释要求,为需要暴露 ...
- 极其简单的帮你理解ORM中的关联关系
ORM对象关系映射(英语:(Object Relational Mapping,简称ORM,或O/RM,或O/R mapping),是一种程序技术,用于实现面向对象编程语言里不同类型系统的数据之间的转 ...
- Alpha冲刺——Day1
一.合照 二.项目燃尽图 三.项目进展 1.界面设计:图形界面部分完成 2.数据库设计:数据库设计基本完成 3.搭建基本服务器框架 github链接 四.明日规划 1.继续完成剩下的图形界面 2.An ...
- beta冲刺3
一,昨天的问题: 页面整理还没做 我的社团这边的后台数据库未完成,前端代码修改未完成. 二,今天已完成 页面整理基本完成,把登陆独立出来了,然后基本处理掉了多余页面(反正也没几个--) 我的社团这边试 ...
- 网络1711班 C语言第四次作业批改总结
网络1711班 C语言第四次作业批改总结 助教有话说(写在前面) 近来,有同学跟老师和助教们反映:博客作业太多太麻烦,而且对编程能力提高似乎没什么帮助?在这里我要谈一谈我的感想. 博客作业的意义? 首 ...
- 【评分】集美大学软件工程1413班工程项目管理个人作业2——APP案例分析
[评分]个人作业2--APP案例分析 作业要求 作业地址及完成情况 博文要求 通过分析你选中的产品,结合阅读<构建之法>,写一篇随笔,包含下述三个环节的所有要求. 第一部分 调研, 评测 ...