探索FSM (有限状态机)应用-全球观焦点
我们是袋鼠云数栈 UED 团队,致力于打造优秀的一站式数据中台产品。我们始终保持工匠精神,探索前端道路,为社区积累并传播经验价值。。
(相关资料图)
本文作者:木杪
有限状态机(FSM)是计算机科学中的一种数学模型,可用于表示和控制系统的行为。它由一组状态以及定义在这些状态上的转换函数组成。FSM 被广泛用于计算机程序中的状态机制。
有限状态机(FSM)应用场景在各种自动化系统的应用:例如交通信号灯、地铁站的旋转闸门、银行自动取款机等。通过对状态和转换函数的定义,可以实现对系统行为的精确控制。
交通信号灯状态流转图
地铁站的旋转闸门状态流转图
银行自动取款机状态流转图
在编程领域的应用:例如在编写编译器和解释器时,可以使用有限状态机(FSM)来处理词法分析。例如:JSON.Parse
在Notion中应用:可以使用 有限状态机(FSM)的相关概念来构建各种工作流程,例如状态转换图、状态转换表等。
在web中应用:我们熟悉的 Promise也是一个状态机,具有三个状态:pending、resolved。rejected。
Promise状态流转图
登录功能流转图
类似这样的状态机的例子数不胜数,甚至于,人也是一种极其复杂的状态机,给定一种刺激或多种刺激组合,也会触发人从某种状态过渡到另一种状态。只不过复杂程度极高,以至于现代科学完全无法解密这种状态机。
有限状态机(FSM)实现原理具体来说,FSM由以下几部分组成:
初始状态:系统的初始状态。状态集合:表示系统可能处于的各种状态。转移函数:定义系统在不同状态之间的转移条件和结果。终止状态:系统在某个状态下可以停止计算。有限状态机(FSM)的实现基于状态转移图。状态转移图是一个有向图,它表示有限状态机(FSM)中状态之间的转移关系。在状态转移图中,每个状态表示系统的某种状态,每个转移表示系统从一个状态转移到另一个状态的条件和结果。
实现简易的有限状态机(FSM)实现步骤当状态机开始执行时,它会自动进入初始化状态(initial state)。每个状态都可以定义,在进入(onEnter)或退出(onExit)该状态时发生的行为事件(actions),通常这些行为事件会携带副作用(side effect)。每个状态都可以定义触发转换(transition)的事件。转换定义了在退出一个状态并进入另一个状态时,状态机该如何处理这种事件。在状态转换发生时,可以定义可以触发的行为事件,从而一般用来表达其副作用。状态转移图function createMachine(stateMachineDefinition) {  const machine = {    value: stateMachineDefinition.initialState,    performTransition(currentState, event) {      const currentStateDefinition = stateMachineDefinition[currentState];      const destinationTransition = currentStateDefinition.transitions[event];      if (!destinationTransition) {        return;      }      const destinationState = destinationTransition.target;      const destinationStateDefinition =        stateMachineDefinition[destinationState];      destinationTransition.action();      currentStateDefinition.actions.onExit();      destinationStateDefinition.actions.onEnter();      machine.value = destinationState;      return machine.value;    },  };  return machine;}const machine = createMachine({  initialState: "off",  off: {    actions: {      onEnter() {        console.log("off: onEnter");      },      onExit() {        console.log("off: onExit");      },    },    transitions: {      switch: {        target: "on",        action() {          console.log("transition action for "switch" in "off" state");        },      },    },  },  on: {    actions: {      onEnter() {        console.log("on: onEnter");      },      onExit() {        console.log("on: onExit");      },    },    transitions: {      switch: {        target: "off",        action() {          console.log("transition action for "switch" in "on" state");        },      },    },  },});let state = machine.value;console.log(`current state: ${state}`);state = machine.performTransition(state, "switch");console.log(`current state: ${state}`);state = machine.performTransition(state, "switch");console.log(`current state: ${state}`);文本解析器实现思路确定状态和输入在编写 FSM 之前,我们需要确定我们的状态和输入。在这个例子中,我们将定义三个状态:起始状态、数字状态和字符串状态。我们还将定义四个输入:数字、字母、引号和空格。定义状态机类现在,我们可以编写代码来实现我们的 FSM 。我们需要定义一个状态机类,它将接受输入,并根据转移规则转换状态。该类应该包含以下属性:在状态比较多的情况下,把状态、事件及 transitions集中到一个状态机中,进行统一管理。这样不需要写太多的 if-else,或者 case判断,如果增加状态和事件,也便于代码的维护和扩展。
currentState:当前状态。states:状态列表。transitions:转移列表。它还应该包含以下方法:transition:该方法接受一个输入参数 input,根据当前状态以及输入参数,执行相应的状态转换。定义转移规则我们还需要定义状态之间的转移规则。为此,我们将使用转移列表,其中包含状态之间的映射和输入。转移规则应该考虑当前状态和输入,并根据它们确定下一个状态。如果当前状态和输入没有匹配的转移规则,则应该抛出一个异常。解析文本现在,我们可以使用状态机解析文本。我们需要将文本拆分为单词,并将每个单词作为输入提供给状态机。在处理完所有输入后,我们可以通过调用 getInputType方法来获取解析的令牌。示例代码const STATES = {  START: "start",  NUMBER: "number",  STRING: "string",};const INPUTS = {  NUMBER: "number",  LETTER: "letter",  SPACE: "space",  QUOTE: "quote",};const TRANSITIONS = [  {    currentState: STATES.START,    input: INPUTS.NUMBER,    nextState: STATES.NUMBER,  },  {    currentState: STATES.START,    input: INPUTS.LETTER,    nextState: STATES.STRING,  },  { currentState: STATES.START, input: INPUTS.SPACE, nextState: STATES.START },  { currentState: STATES.START, input: INPUTS.QUOTE, nextState: STATES.STRING },  {    currentState: STATES.NUMBER,    input: INPUTS.NUMBER,    nextState: STATES.NUMBER,  },  { currentState: STATES.NUMBER, input: INPUTS.SPACE, nextState: STATES.START },  {    currentState: STATES.STRING,    input: INPUTS.LETTER,    nextState: STATES.STRING,  },  { currentState: STATES.STRING, input: INPUTS.SPACE, nextState: STATES.START },  { currentState: STATES.STRING, input: INPUTS.QUOTE, nextState: STATES.START },];class TextParse {  constructor() {    this.currentState = STATES.START;    this.buffer = "";    this.type;  }  performTransition(input) {    const transition = TRANSITIONS.find(      (t) => t.currentState === this.currentState && t.input === input.type    );    if (!transition)      throw new Error(        `Invalid input "${input.value}" for state "${this.currentState}"`      );    this.currentState = transition.nextState;    if (this.currentState === STATES.START) {      const token = this.buffer;      const type = this.type;      this.buffer = "";      this.type = "";      return {        type,        value: token,      };    } else {      this.buffer += input.value;      this.type = input.type;    }  }}function textParse(input) {  const textParse = new TextParse();  const tokens = [];  for (let i = 0; i < input.length; i++) {    const char = input[i];    try {      const token = textParse.performTransition({        type: getInputType(char),        value: char,      });      if (token) {        tokens.push(token);      }    } catch (e) {      console.error(e.message);      return null;    }  }    const lastToken = textParse.performTransition({ type: INPUTS.SPACE });  if (lastToken) {    tokens.push(lastToken);  }  return tokens;}function getInputType(char) {  if (/[0-9]/.test(char)) {    return INPUTS.NUMBER;  } else if (/[a-zA-Z]/.test(char)) {    return INPUTS.LETTER;  } else if (/[\s\n\t\r]/.test(char)) {    return INPUTS.SPACE;  } else if (char === """) {    return INPUTS.QUOTE;  } else {    throw new Error(`Unknown input type for "${char}"`);  }}// Example usage:console.log(textParse("123 abc "def ghi" 456")); // [//   { type: "number", value: "123" },//   { type: "letter", value: "abc" },//   { type: "letter", value: ""def" },//   { type: "letter", value: "ghi" },//   { type: "", value: "" },//   { type: "number", value: "456" }// ]示例代码
web 应用使用 有限状态机(FSM)结合 React构建 web 应用,不局限于身份认证,登录,步骤表单,有蛮多 web 应用在有限状态机(FSM)的实践,下面主要描述 从有限状态机(FSM)在服务端拉取数据的状态转移上的应用
状态转移图
状态集(States), 转换规则(Transitions)
const states = {  INITIAL: "idle",  LOADING: "loading",  SUCCESS: "success",  FAILURE: "failure",};const transitions = {  [states.INITIAL]: {    fetch: () => /* Returns states.LOADING */,  },  [states.LOADING]: {},  [states.SUCCESS]: {    reload: () => /* Returns states.LOADING */,    clear: () => /* Returns states.INITIAL */,  },  [states.FAILURE]: {    retry: () => /* Returns states.LOADING */,    clear: () => /* Returns states.INITIAL */,  },}示例代码
总结结合前端应用的探索体现的不多,可以再作为第二篇内容去探讨,有兴趣的同学可以尝试一下 有限状态机(FSM)在 web 上的应用探索,以及 Xstate库(FSM封装的功能性库)的应用,以及跟 状态管理库差异化的知识。在这里提醒一点,状态管理库 (Redux)和 Xstate并不是互斥的,Xstate关注的是如何设计状态,状态管理库关注的是如何管理状态。事实上,状态机几乎可以与任何无主见的状态管理工具一起使用。我鼓励您探索各种方法,以确定最适合您、您的团队和您的应用程序的方法。
参考资料https://statecharts.dev/what-is-a-state-machine.htmlhttps://bespoyasov.me/blog/fsm-to-the-rescue/https://xstate.js.org/docs/about/concepts.htmlhttps://kentcdodds.com/blog/implementing-a-simple-state-machine-library-in-javascripthttps://css-tricks.com/finite-state-machines-with-react/- 
                                  探索FSM (有限状态机)应用-全球观焦点博客园 2023-04-21 
- 
                                  世界关注:浙江长兴:抓住春天的尾巴中国教育新闻网 2023-04-21 
- 
                                  环球热点评!助推三农新跨越 “大美雁江乡村行”活动启动四川经济网 2023-04-21 
- 
                                  读书|一书一馆,看博物馆里的墨西哥古代史文汇报 2023-04-21 
- 
                                  半场战报-斯坦丘造险谢鹏飞失必进球 三镇暂时0-0国安 全球热点射门中国 2023-04-21 
- 
                                  记者帮办|西安地铁八号线环保喷淋设备喷淋行人 施工方:会尽快调整西部网(陕西新闻网) 2023-04-21 
- 
                                  厦门见证补贴咨询电话一览|环球新要闻本地宝 2023-04-21 
- 
                                  今热点:研究:美国多个城市正遭受高通胀打击 居民面临沉重生活负担海外网 2023-04-21 
- 
                                  世界速讯:韩媒:俄方抗议韩国可能武器援乌,韩总统室再度发声解释环球网 2023-04-21 
- 
                                  天天关注:2023天津中超联赛积分榜(最新)本地宝 2023-04-21 
- 
                                  探索FSM (有限状态机)应用-全球观焦点博客园 2023-04-21 
- 
                                  世界关注:浙江长兴:抓住春天的尾巴中国教育新闻网 2023-04-21 
- 
                                  环球热点评!助推三农新跨越 “大美雁江乡村行”活动启动四川经济网 2023-04-21 
- 
                                  读书|一书一馆,看博物馆里的墨西哥古代史文汇报 2023-04-21 
- 
                                  半场战报-斯坦丘造险谢鹏飞失必进球 三镇暂时0-0国安 全球热点射门中国 2023-04-21 
- 
                                  记者帮办|西安地铁八号线环保喷淋设备喷淋行人 施工方:会尽快调整西部网(陕西新闻网) 2023-04-21 
- 
                                  厦门见证补贴咨询电话一览|环球新要闻本地宝 2023-04-21 
- 
                                  今热点:研究:美国多个城市正遭受高通胀打击 居民面临沉重生活负担海外网 2023-04-21 
- 
                                  世界速讯:韩媒:俄方抗议韩国可能武器援乌,韩总统室再度发声解释环球网 2023-04-21 
- 
                                  天天关注:2023天津中超联赛积分榜(最新)本地宝 2023-04-21 
- 
                                  美联储推出即时支付系统FedNow|每日速看云掌财经海投全球 2023-04-20 
- 
                                  西南民族大学音乐类录取分数线(西南民族大学录取分数线)互联网 2023-04-20 
- 
                                  云南广南原副县长高燕文落马细节:家门口脚垫丢失要求出警,视下属为自家仆从北晚在线 2023-04-20 
- 
                                  太平臻爱金生终身寿险条款,太平臻爱金生终身寿险能取出吗|报道沃保网编辑整理 2023-04-20 
- 
                                  世界短讯!“外卖诗人”15万公里写下4000首诗中国青年报客户端 2023-04-20 
- 
                                  科幻灾难电影《全城风暴》热映 王沐暄爆发演技受好评北青网 2023-04-20 
- 
                                  “20cm”涨停!寒武纪最新总市值突破1100亿元关口-世界观天下财经网 2023-04-20 
- 
                                  厦大沙坡尾片区人气攀升 大学路3路口微改造通行提速_环球微头条厦门日报 2023-04-20 
- 
                                  狄龙16岁旧推被挖出:詹姆斯联盟最强 他很伟大你们都知道天下足球最新帖子 2023-04-20 
- 
                                  VR探城⑲丨成都大运会倒计时100天 带你空中360°一瞰大运宝藏场馆_世界看点川观新闻 2023-04-20 
- 
                                  安徽宁国出台鼓励生育举措:生二孩补贴10000元,生三孩补贴15000元DoNews快讯 2023-04-20 
- 
                                  充足电力绘就春耕生产美丽画卷——国网榆林供电公司服务春耕春灌侧记 世界讯息西北信息报社 2023-04-20 
- 
                                  杭州自驾去成都怎么安排(杭州自驾去成都怎么安排的) 每日快报环球旅程网 2023-04-20 
- 
                                  农业农村部:全国农产品批发市场猪肉平均价格比昨天下降0.6% 世界新动态证券时报 2023-04-20 
- 
                                  农业农村部:力争今年全国大豆亩产提高5公斤 精选界面新闻 2023-04-20 
- 
                                  特斯拉发布一季报 预计车辆成本将持续降低新京报 2023-04-20 
- 
                                  焦点关注:央行今日进行340亿元7天期逆回购操作界面新闻 2023-04-20 
- 
                                  当前关注:石家庄老庙黄金多少钱一克(2023年4月20日)金投网 2023-04-20 
- 
                                  狂飙25记三分!雄鹿追平季后赛单场三分纪录,一打热火就开挂鲁能资讯 2023-04-20 
- 
                                  同济堂索赔时效即将到期 投资者勿忘报名参与大众证券报 2023-04-20