XState Viz 可视化和调试状态机
1. 前言
狀態(tài)機(jī)的一大好處就是可以可視化狀態(tài),降低業(yè)務(wù)的理解成本和相互間的溝通成本。
目前 XState 官方提供的可視化工具已經(jīng)做的很不錯(cuò)了,但用起來(lái)偏重,國(guó)內(nèi)訪問(wèn)也比較慢。這邊我再原基礎(chǔ)上進(jìn)行了優(yōu)化,并增加了部分新功能,開(kāi)發(fā)了 Viz-Lite 版。
2. Viz-Lite
Viz-Lite 可視化工具地址
主要有如下功能:
- 直接在右側(cè)區(qū)域進(jìn)行編寫(xiě)或粘貼 XState 狀態(tài)機(jī)代碼,右側(cè)進(jìn)行可視化。
- 可以在左側(cè)可視化區(qū)域通過(guò)點(diǎn)擊進(jìn)行狀態(tài)機(jī)執(zhí)行。
- 可以在右側(cè)事件面板中查看事件歷史,且可以手動(dòng)進(jìn)行自定義事件發(fā)送。
- 可以通過(guò) @xstate/inspect 與頁(yè)面中的狀態(tài)機(jī)實(shí)時(shí)建立連接,可視化查看當(dāng)前頁(yè)面狀態(tài)機(jī)細(xì)節(jié)。
- 可以將可視化出來(lái)的狀態(tài)圖進(jìn)行圖片導(dǎo)出。
- 可以切切亮/暗色。
等等。
3. Inspect 底層實(shí)現(xiàn)
Viz-Lite 可以實(shí)時(shí)與頁(yè)面中的狀態(tài)圖建立數(shù)據(jù)連接,需要依賴 @xstate/inspect,且在頁(yè)面、Inspect、Viz-Lite 建立有嚴(yán)格的依賴關(guān)系。
我大致梳理了一下三者的關(guān)系,如下的序列圖所示:
#mermaid-svg-86dzAJtVjnO1JwiF {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-86dzAJtVjnO1JwiF .error-icon{fill:#552222;}#mermaid-svg-86dzAJtVjnO1JwiF .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-86dzAJtVjnO1JwiF .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-86dzAJtVjnO1JwiF .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-86dzAJtVjnO1JwiF .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-86dzAJtVjnO1JwiF .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-86dzAJtVjnO1JwiF .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-86dzAJtVjnO1JwiF .marker{fill:#333333;stroke:#333333;}#mermaid-svg-86dzAJtVjnO1JwiF .marker.cross{stroke:#333333;}#mermaid-svg-86dzAJtVjnO1JwiF svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-86dzAJtVjnO1JwiF .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-86dzAJtVjnO1JwiF text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-86dzAJtVjnO1JwiF .actor-line{stroke:grey;}#mermaid-svg-86dzAJtVjnO1JwiF .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-86dzAJtVjnO1JwiF .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-86dzAJtVjnO1JwiF #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-86dzAJtVjnO1JwiF .sequenceNumber{fill:white;}#mermaid-svg-86dzAJtVjnO1JwiF #sequencenumber{fill:#333;}#mermaid-svg-86dzAJtVjnO1JwiF #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-86dzAJtVjnO1JwiF .messageText{fill:#333;stroke:#333;}#mermaid-svg-86dzAJtVjnO1JwiF .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-86dzAJtVjnO1JwiF .labelText,#mermaid-svg-86dzAJtVjnO1JwiF .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-86dzAJtVjnO1JwiF .loopText,#mermaid-svg-86dzAJtVjnO1JwiF .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-86dzAJtVjnO1JwiF .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-86dzAJtVjnO1JwiF .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-86dzAJtVjnO1JwiF .noteText,#mermaid-svg-86dzAJtVjnO1JwiF .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-86dzAJtVjnO1JwiF .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-86dzAJtVjnO1JwiF .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-86dzAJtVjnO1JwiF .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-86dzAJtVjnO1JwiF .actorPopupMenu{position:absolute;}#mermaid-svg-86dzAJtVjnO1JwiF .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-86dzAJtVjnO1JwiF .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-86dzAJtVjnO1JwiF .actor-man circle,#mermaid-svg-86dzAJtVjnO1JwiF line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-86dzAJtVjnO1JwiF :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}VizInspectInterpreter開(kāi)啟 Inspect 并打開(kāi) Viz 工具全局注入 __xstate__打開(kāi) VizInspect.createWindowReceiver()send('xstate.inspecting')打開(kāi)狀態(tài)機(jī)服務(wù)并與注冊(cè)到 Inspect__REDUX_DEVTOOLS_EXTENSION__registerService(this)send('service.registe')send('service.registe')send('service.registe', {sessionId})三者建立連接alt[has __xstate__]VizInspectInterpreter類(lèi)似于 HTTP 三次握手。
在 Viz-Lite 中建立連接主要依靠 @xstate/inspect 的 createWindowReceiver 方法。
Viz-Lite 向 頁(yè)面狀態(tài)機(jī)發(fā)送事件,可以使用 createWindowReceiver 返回值中的 send 方法,消息體中 type 必須是 xstate.event。
頁(yè)面中狀態(tài)機(jī)的變化,可以通過(guò) createWindowReceiver 返回值中的 subscribe 方法進(jìn)行訂閱,包括 service.state 和 service.event。監(jiān)聽(tīng) service.stop 可以確定連接的斷開(kāi)。
4. 接入調(diào)試方法
安裝 @xstate/inspect:
npm i -S @xstate/inspect從上面的序列圖中也可以看出,inspect 必須在 interpret() 之前執(zhí)行,不然無(wú)法連接:
import { inspect } from '@xstate/inspect';inspect({url: 'https://apis.leping.fun/viz?inspect',iframe: false });- url 中指定 Viz-Lite 的地址 https://apis.leping.fun/viz?inspect。
- iframe 指定在哪里掛載 Viz-Lite。可以直接指定一個(gè) DOM,也可以設(shè)置為 false,瀏覽器會(huì)打開(kāi)一個(gè)新頁(yè)面。
注意:調(diào)試模式,必須在 Viz-Lite 的地址中加上 ?inspect。如果想默認(rèn)關(guān)閉右側(cè)面板可以加上 ?inspect&panel=false。
然后在創(chuàng)建狀態(tài)機(jī)服務(wù)時(shí),指定 devTools 標(biāo)志位就可以了:
import { interpret } from 'xstate';const service = interpret(someMachine, { devTools: true });可以訪問(wèn)這個(gè) 地址 查看效果:
Github 代碼地址
5. 快捷鍵
- + / - 或者 CMD + 滾輪上/下:縮放。
- CMD + Enter: 可視化當(dāng)前代碼。
- ↑↓←→:平移視圖。同時(shí)按住 Shift,增大平移服毒。
- Shift + 1:適配到到窗口大小。
6. 配合 Redux DevTools 使用
從序列圖中可以看到在開(kāi)啟 devTools: true 的時(shí)候,會(huì)判斷是否有 __REDUX_DEVTOOLS_EXTENSION__,如果有的話也可以在 Redux DevTools 中查看事件信息,如下圖所示:
? 原文地址
總結(jié)
以上是生活随笔為你收集整理的XState Viz 可视化和调试状态机的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 【预测模型】基于Elman神经网络预测电
- 下一篇: 【我们都爱Paul Hegarty】斯坦