XState Viz 可视化和调试状态机
1. 前言
狀態機的一大好處就是可以可視化狀態,降低業務的理解成本和相互間的溝通成本。
目前 XState 官方提供的可視化工具已經做的很不錯了,但用起來偏重,國內訪問也比較慢。這邊我再原基礎上進行了優化,并增加了部分新功能,開發了 Viz-Lite 版。
2. Viz-Lite
Viz-Lite 可視化工具地址
主要有如下功能:
- 直接在右側區域進行編寫或粘貼 XState 狀態機代碼,右側進行可視化。
- 可以在左側可視化區域通過點擊進行狀態機執行。
- 可以在右側事件面板中查看事件歷史,且可以手動進行自定義事件發送。
- 可以通過 @xstate/inspect 與頁面中的狀態機實時建立連接,可視化查看當前頁面狀態機細節。
- 可以將可視化出來的狀態圖進行圖片導出。
- 可以切切亮/暗色。
等等。
3. Inspect 底層實現
Viz-Lite 可以實時與頁面中的狀態圖建立數據連接,需要依賴 @xstate/inspect,且在頁面、Inspect、Viz-Lite 建立有嚴格的依賴關系。
我大致梳理了一下三者的關系,如下的序列圖所示:
#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開啟 Inspect 并打開 Viz 工具全局注入 __xstate__打開 VizInspect.createWindowReceiver()send('xstate.inspecting')打開狀態機服務并與注冊到 Inspect__REDUX_DEVTOOLS_EXTENSION__registerService(this)send('service.registe')send('service.registe')send('service.registe', {sessionId})三者建立連接alt[has __xstate__]VizInspectInterpreter類似于 HTTP 三次握手。
在 Viz-Lite 中建立連接主要依靠 @xstate/inspect 的 createWindowReceiver 方法。
Viz-Lite 向 頁面狀態機發送事件,可以使用 createWindowReceiver 返回值中的 send 方法,消息體中 type 必須是 xstate.event。
頁面中狀態機的變化,可以通過 createWindowReceiver 返回值中的 subscribe 方法進行訂閱,包括 service.state 和 service.event。監聽 service.stop 可以確定連接的斷開。
4. 接入調試方法
安裝 @xstate/inspect:
npm i -S @xstate/inspect從上面的序列圖中也可以看出,inspect 必須在 interpret() 之前執行,不然無法連接:
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。可以直接指定一個 DOM,也可以設置為 false,瀏覽器會打開一個新頁面。
注意:調試模式,必須在 Viz-Lite 的地址中加上 ?inspect。如果想默認關閉右側面板可以加上 ?inspect&panel=false。
然后在創建狀態機服務時,指定 devTools 標志位就可以了:
import { interpret } from 'xstate';const service = interpret(someMachine, { devTools: true });可以訪問這個 地址 查看效果:
Github 代碼地址
5. 快捷鍵
- + / - 或者 CMD + 滾輪上/下:縮放。
- CMD + Enter: 可視化當前代碼。
- ↑↓←→:平移視圖。同時按住 Shift,增大平移服毒。
- Shift + 1:適配到到窗口大小。
6. 配合 Redux DevTools 使用
從序列圖中可以看到在開啟 devTools: true 的時候,會判斷是否有 __REDUX_DEVTOOLS_EXTENSION__,如果有的話也可以在 Redux DevTools 中查看事件信息,如下圖所示:
? 原文地址
總結
以上是生活随笔為你收集整理的XState Viz 可视化和调试状态机的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【预测模型】基于Elman神经网络预测电
- 下一篇: 【我们都爱Paul Hegarty】斯坦