如何使用有限狀態(tài)機(jī)

1.背景介紹

? ? ? ?有限狀態(tài)機(jī),(英語:Finite-state machine, FSM),又稱為有限狀態(tài)自動機(jī),簡稱狀態(tài)機(jī),是一個(gè)數(shù)學(xué)模型。是一個(gè)抽象機(jī)器,在任何時(shí)候都可以處于有限數(shù)量的狀態(tài)之一。響應(yīng)某些外部輸入,F(xiàn)SM可以從一個(gè)狀態(tài)轉(zhuǎn)換到另一個(gè)狀態(tài);從一種狀態(tài)到另一種狀態(tài)的變化稱為過渡。狀態(tài)機(jī)的行為可以在現(xiàn)代社會中的許多設(shè)備中觀察到,這些設(shè)備根據(jù)它們呈現(xiàn)的事件序列執(zhí)行預(yù)定的一系列行為。例如自動售貨機(jī),當(dāng)存放適當(dāng)?shù)挠矌沤M合時(shí)分配產(chǎn)品,當(dāng)車輛等待時(shí)改變順序的交通燈等。

? ? ? ?有限狀態(tài)機(jī)最初應(yīng)用在數(shù)字系統(tǒng)的涉及,它對數(shù)字系統(tǒng)的設(shè)計(jì)具有十分重要的作用。有限狀態(tài)機(jī)是指輸出取決于過去輸入部分和當(dāng)前輸入部分的時(shí)序邏輯電路。,除了輸入部分和輸出部分外,有限狀態(tài)機(jī)還含有一組具有“記憶”功能的寄存器,這些寄存器的功能是記憶有限狀態(tài)機(jī)的內(nèi)部狀態(tài),它們常被稱為狀態(tài)寄存器。

? ? ? ?在有限狀態(tài)機(jī)中,狀態(tài)寄存器的的下一個(gè)狀態(tài)不僅與輸入信號有關(guān),而且還與該寄存器的當(dāng)前狀態(tài)有關(guān),因此有限狀態(tài)機(jī)又可以認(rèn)為是組合邏輯和寄存器邏輯的一種組合。其中,寄存器邏輯的功能是存儲有限狀態(tài)機(jī)的內(nèi)部狀態(tài);而組合邏輯又可以分為次態(tài)邏輯和輸出邏輯兩部分,次態(tài)邏輯的功能是確定有限狀態(tài)機(jī)的下一個(gè)狀態(tài),輸出邏輯的功能是確定有限狀態(tài)機(jī)的輸出。

? ? ? ? 在我們前端開發(fā)中,我們可以套用有限狀態(tài)機(jī)模型,將業(yè)務(wù)流程狀態(tài)化,劃分狀態(tài)和相應(yīng)的觸發(fā)事件與動作,利用生 命周期事件進(jìn)行控制與執(zhí)行。

一個(gè)可以用狀態(tài)機(jī)模擬的簡單機(jī)制的例子---旋轉(zhuǎn)門。

? ? ? ? ? 常見的旋轉(zhuǎn)門是控制通往地鐵和游樂園的游樂設(shè)施的旋轉(zhuǎn)門。在腰部高度有三個(gè)旋轉(zhuǎn)臂,一個(gè)在入口處。最初狀態(tài),手臂被鎖住了,阻止進(jìn)入,防止顧客通過。將硬幣或代幣存放在旋轉(zhuǎn)門上的一個(gè)槽中,可以打開手臂,讓一位顧客穿過。顧客通過后,手臂再次被鎖定,直到另一枚硬幣被插入。作為一個(gè)狀態(tài)機(jī),旋轉(zhuǎn)門有兩種可能的狀態(tài):鎖定和解鎖。有兩種可能的輸入影響其狀態(tài):將硬幣放入槽(硬幣)并推動手臂(推)。在鎖定狀態(tài)下,推臂不起作用;無論輸入推送有多少次,它都處于鎖定狀態(tài)。投入一枚硬幣-也就是給機(jī)器一個(gè)硬幣輸入-將狀態(tài)從“鎖定”轉(zhuǎn)換為“解鎖”。在解鎖狀態(tài)下,放入額外的硬幣不起作用;那就是增加硬幣輸入不會改變狀態(tài)。但是,一個(gè)推著手臂的顧客,將推送這個(gè)動作輸入,狀態(tài)就轉(zhuǎn)回到鎖定狀態(tài)。


? ? ? ? 旋轉(zhuǎn)門狀態(tài)機(jī)也可以用稱為狀態(tài)圖(上圖)的有向圖表示 。每個(gè)狀態(tài)都由一個(gè)節(jié)點(diǎn)(圓圈)表示。邊(箭頭)顯示從一個(gè)狀態(tài)到另一個(gè)狀態(tài)的轉(zhuǎn)換。每個(gè)箭頭都標(biāo)有觸發(fā)該轉(zhuǎn)換的輸入。不會導(dǎo)致狀態(tài)改變的輸入(例如在解鎖狀態(tài)下的硬幣輸入)由返回到原始狀態(tài)的圓形箭頭表示。從黑點(diǎn)到鎖定節(jié)點(diǎn)的箭頭表示這是初始狀態(tài)。

2.知識剖析

2.1:有限狀態(tài)機(jī)有什么特點(diǎn)

有限狀態(tài)機(jī)fsm一般有以下特點(diǎn):

*)可以用狀態(tài)來描述事物,并且任一時(shí)刻,事物總是處于一種狀態(tài);

*)事物擁有的狀態(tài)總數(shù)是有限的;

*)通過觸發(fā)事物的某些行為,可以導(dǎo)致事物從一種狀態(tài)過渡到另一種狀態(tài);

*)同一種行為,可以將事物從多種狀態(tài)變成同種狀態(tài),但是不能從同種狀態(tài)變成多種狀態(tài)。

2.2:有限狀態(tài)機(jī)的組成

2.2.1、狀態(tài)機(jī)由一組狀態(tài)和轉(zhuǎn)換組成例如:

need-to-insert-img

狀態(tài):固體 、 液體 、 氣體。

轉(zhuǎn)換 :融化 、汽化 、 冷凝 、 凍結(jié)。


2.2.2、有限狀態(tài)機(jī)形式(有限狀態(tài)機(jī)長什么樣)

1、需要的函數(shù)庫:javascript-state-machine插件。

2、生成實(shí)例,創(chuàng)建生命周期:

var fsm = new StateMachine({

init: 'solid',

transitions: [

{name: 'Melt', from: 'solid', to: 'liquid'},

{name: 'Vaporize', from: 'liquid', to: 'gas'},

{name: 'Condense', from: 'gas', to: 'liquid'},

{name: 'Freeze', from: 'liquid', to: 'solid'}

],

methods: {

onBeforeMelt:? ? ? ? function() { /* ... */ },

onBeforeVaporize:? ? function() { /* ... */ },

onBeforeCondense:? ? function() { /* ... */ },

onBeforeFreeze:? ? ? function() { /* ... */ },

onLeaveSolid:? ? ? ? function() { /* ... */ },

onLeaveLiquid:? ? ? ? function() { /* ... */ },

onLeaveGas:? ? ? ? ? function() { /* ... */ },

onEnterLiquid:? ? ? ? function() { /* ... */ },

onEnterGas:? ? ? ? ? function() { /* ... */ },

onEnterSolid:? ? ? ? function() { /* ... */ },

onAfterMelt:? ? ? ? ? function() { /* ... */ },

onAfterVaporise:? ? ? function() { /* ... */ },

onAfterCondense:? ? ? function() { /* ... */ }

onAfterFreeze:? ? ? ? function() { /* ... */ }

}

});

//方法調(diào)用

//1,自執(zhí)行方法:

fsm.onMelt();

fsm.onVaporize();

fsm.onCondense();

fsm.onFreeze();

//1、觸發(fā)調(diào)用方式:

fsm.Melt();

fsm.Vaporize();

fsm.Condense();

fsm.Freeze();


HTML代碼:

有限狀態(tài)機(jī)包含以下基本內(nèi)容:

1、初始狀態(tài)init:init選項(xiàng)用來表示fsm對象的初始狀態(tài),

2、轉(zhuǎn)換規(guī)則transitions:transitions選項(xiàng)用來描述fsm對象所有狀態(tài)的變化規(guī)則,每一種變化規(guī)則對應(yīng)一種行為。

3、方法methods:methods方法為實(shí)例的每一種行為都添加了一個(gè)方法,調(diào)用這個(gè)方法就相當(dāng)于觸發(fā)對象的某種行為,當(dāng)對象行為發(fā)生時(shí),對象的狀態(tài)就可以發(fā)生變化。

如以上例子創(chuàng)建的實(shí)例將擁有如下行為方法:

fsm.Melt() :調(diào)用該方法,實(shí)例狀態(tài)將從'solid'變?yōu)?liquid'

fsm.Freeze() :調(diào)用該方法,實(shí)例狀態(tài)將從'liquid'變?yōu)?solid'

fsm.Vaporize() :調(diào)用該方法,實(shí)例狀態(tài)將從'liquid'變?yōu)?gas'

fsm.Condense() :調(diào)用該方法,實(shí)例狀態(tài)將從'gas'變?yōu)?liquid'

2.2.3、有限狀態(tài)機(jī)的方法

Javascript Finite State Machine允許為每個(gè)事件指定兩個(gè)自定義方法,以Melt事件為例:

onbeforeMelt:在warn事件發(fā)生之前觸發(fā)

onafterMelt:在warn事件發(fā)生之后觸發(fā)。

每個(gè)狀態(tài)指定兩個(gè)自定義方法,以solid狀態(tài)為例:

onleaveSolid:在離開solid狀態(tài)時(shí)觸發(fā)

onenterLiquid:在進(jìn)入liquid狀態(tài)時(shí)觸發(fā)。

2.2.4、通用的生命周期事件

為了在發(fā)生轉(zhuǎn)換時(shí)跟蹤或執(zhí)行操作,有以下五個(gè)通用的生命周期事件:

// onBeforeTransition -在任何轉(zhuǎn)換之前觸發(fā)

// onLeaveState -離開任何狀態(tài)被觸發(fā)

// onTransition -在任何過渡期間被觸發(fā)

// onEnterState -進(jìn)入任何狀態(tài)被觸發(fā)

// onAfterTransition -任何轉(zhuǎn)換后觸發(fā)

2.2.5、特定的轉(zhuǎn)換和狀態(tài)

除了通用事件之外,還可以使用特定的轉(zhuǎn)換和狀態(tài)來觀察轉(zhuǎn)換:

// onBefore-在特定的轉(zhuǎn)換之前觸發(fā)

// onBefore-在特定的轉(zhuǎn)換之前觸發(fā)

// onAfter-在特定的TRANSITION后觸發(fā)

// onLeave-離開特定的狀態(tài)觸發(fā)

// onEnter-進(jìn)入特定狀態(tài)觸發(fā)

// on-簡寫onAfter

// on-簡寫onEnter

2.2.6、輔助方法:

// fsm.is(s) -如果狀態(tài)s是當(dāng)前狀態(tài),則返回true

// fsm.can(t) -如果t從當(dāng)前狀態(tài)發(fā)生轉(zhuǎn)換,則返回true

// fsm.cannot(t) -如果t從當(dāng)前狀態(tài)不能發(fā)生轉(zhuǎn)換,則返回true

// fsm.transitions() -返回當(dāng)前狀態(tài)允許的轉(zhuǎn)換列表

// fsm.allTransitions() -返回所有可能的轉(zhuǎn)換的列表

// fsm.allStates() -返回所有可能狀態(tài)的列表

//Cancelling a Transition取消轉(zhuǎn)換

2.2.7、可以通過false在以下任何生命周期事件中顯式返回來取消轉(zhuǎn)換

在方法中return false可以取消當(dāng)前觸發(fā)的行為:

// onBeforeTransition

// onBefore

// onLeaveState

// onLeave

// onTransition

//所有隨后的生命周期事件將被取消,狀態(tài)將保持不變。

3.常見問題

如何使用有限狀態(tài)機(jī)

4 解決方案

首先創(chuàng)建fsm實(shí)例----設(shè)置初始初始狀態(tài)------規(guī)定轉(zhuǎn)換規(guī)則------定義方法。

var fsm = new StateMachine({? ? ? ? ? //創(chuàng)建fsm實(shí)例

init: 'solid',? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //設(shè)置初始狀態(tài)

transitions: [? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?//定義裝換規(guī)則

{name: 'Melt', from: 'solid', to: 'liquid'},

{name: 'Vaporize', from: 'liquid', to: 'gas'},

{name: 'Condense', from: 'gas', to: 'liquid'},

{name: 'Freeze', from: 'liquid', to: 'solid'}

],

methods: {? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //定義方法

onBeforeMelt:? ? ? ? function() { /* ... */ },

onLeaveSolid:? ? ? ? function() { /* ... */ },

onEnterLiquid:? ? ? ? function() { /* ... */ },

onAfterMelt:? ? ? ? ? function() { /* ... */ },

}

});

//觸發(fā)轉(zhuǎn)換

fsm.Melt();

fsm.Vaporize();

fsm.Condense();

fsm.Freeze();

6.擴(kuò)展思考

Javascript Finite State Machine 的異步轉(zhuǎn)換

有時(shí),我們需要在狀態(tài)轉(zhuǎn)換期間執(zhí)行一些異步代碼,并確保在代碼完成之前不會輸入新狀態(tài)。

舉個(gè)栗子:

當(dāng)我們從一個(gè)狀態(tài)轉(zhuǎn)換出來并想逐漸淡入一個(gè)UI組件,或者將它從屏幕上滑出來,而且不想在動畫完成之后轉(zhuǎn)換到下一個(gè)狀態(tài)。就可以通過 從任何生命周期事件中返回Promise對象來實(shí)現(xiàn)此目的。從生命周期事件返回Promise將導(dǎo)致該轉(zhuǎn)換的生命周期暫停??梢岳^續(xù)解決,也可以拒絕承諾。

7.參考文獻(xiàn)

一、官方文檔https://github.com/jakesgordon/javascript-state-machine/blob/master/docs/states-and-transitions.md

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容