本文經過設計一個簡單的任務中心來展現一個使用有限狀態機思想設計該如何作。前端
本文使用 JSDOC 添加註釋。git
有限狀態機 (FSM) 維基 百度百科 是用來表示有限個狀態及在這些狀態之間轉移和動做的數學模型。早在07年就有文章講解 js 與狀態機的結合。github
在程序中,咱們用這種數學模型抽象業務的複雜行爲。做爲狀態機,有如下特徵特色:bash
任務中心具備如下功能:架構
若是針對以上需求,整理整個流程, 能夠認爲任務中心的流程以下:測試
由於需求中存在「能夠在任什麼時候間塞入任務」,因此對於不一樣的流程設定任務的不一樣執行狀態。ui
分離了任務中心和任務,這兩種並行的狀態,咱們就能夠分開設計,分開編碼了。編碼
那麼先作任務中心組件的實際設計,關於這個組件可能有的狀態以下:spa
初始狀態設計
運行狀態
暫停狀態
恢復狀態
恢復後的運行狀態
中止狀態
重啓狀態
........
但因爲咱們組件有的功能,咱們僅爲組件設計了四個狀態就能夠描述其整個生命流程:
由於咱們的這個任務中心是給任務調度用的,因此僅跟任務有關的狀態纔是有用的狀態,這也是狀態機設計思惟的核心之一,僅設計使用相關聯的狀態, 並保證剩餘的狀態可成爲完整的流程, 任務中心的四個狀態組成流程以下圖所示:
爲了更好的展現事務狀態,咱們在組件狀態切換中加入明確的狀態標識。並在類的狀態列表定義它們:
/** * 枚舉 InstantTask 組件狀態 * @enum {Number} * @readonly */
InstantTask.State = Object.freeze({
/** * @memberof InstantTask.State * @type {Number} */
IDLE: 0,
/** * @memberof InstantTask.State * @type {Number} */
RUNNING: 1,
/** * @memberof InstantTask.State * @type {Number} */
PAUSED: 2,
/** * @memberof InstantTask.State * @type {Number} */
STOPPED: 3,
});
複製代碼
組件一共存在五個行爲, 這些行爲在數學中能夠被認爲是變換器,它們就是上述狀態機運轉圖的具體行爲體現。
start()
用於啓動組件,設置組件爲 RUNNING
狀態。
上一個狀態能夠是任何狀態。
用於啓動任務中心,並會執行全部以前塞入並無被執行的任務
pause()
用於暫停組件,設置組件爲 PAUSED
狀態。
上一個狀態只能是 RUNNING
狀態。
用於暫停任務中心,在暫停後任何任務塞入也不會被執行
resume()
用於恢復組件的暫停狀態,設置組件爲 RUNNING
狀態
上一個狀態只能是 PAUSED
狀態
用於啓動任務中心,並會執行全部以前塞入並無被執行的任務,和start()之間功能差距不大,可是不會像start()同樣重置全部設定,並且主要用途是和pause方法作一一對應。一個方法或者狀態的多用途對於狀態機設計來講會增長架構複雜度,儘可能避免吧。
stop()
用於中止任務中心,設置組件爲 STOPPED
狀態
上一個狀態只能是 RUNNING
狀態
用於中止任務中心,和pause的區別是它會記錄中止狀態,而且不能被resume,和pause內部邏輯差距不大。主用途是和start()作對立方法。
reset()
用於重置任務中心,設置組件爲 IDLE
狀態
上一個狀態能夠是任何狀態, 但主要是 STOPPED
狀態
用於重置任務中心,此方法等於生成一個新的任務中心。
當咱們肯定組件的抽象運行狀態和運行行爲後,就能夠結合實際業務邏輯來實現具體的組件了。 本文中使用 EventEmitter
來做爲事件的廣播和處理,前端也能夠借用 eventemitter3
這樣的近似的類實現一樣的功能。
同時接下來本文使用代碼中註釋的方式繼續說明每一個方法的詳細用途:
具體代碼已經放在: https://gist.github.com/Suixinlei/4b2da4ee1ef84e89b5cfccc1b88b3e4f
測試代碼放在: https://gist.github.com/Suixinlei/d8441babe5174b7b1d4326f39b0fcff2
測試結果以下所示,咱們能夠看到實際運行結果和咱們的抽象設計徹底一致,充分證實抽象設計對最終邏輯的影響:
添加任務 instant1
添加任務 instant2
任務中心開始運行
instant1 run
instant2 run
添加任務 instant3
instant3 run
任務中心已暫停
添加任務 instant4
恢復運行
instant4 run
複製代碼
目前來講,全部任務都是即時任務,因此對於任務中心的狀態僅有四種便可知足需求。若是這些任務有一些是定時任務,甚至能夠循環執行並規定執行次數呢?讀完這篇文章我想你心中應該已經有些想法, 那麼看看下面的最終實現和你想的是否有些出入呢?
這裏是最終實現: https://gist.github.com/Suixinlei/e245812799fa160cdf0bbcdf279e68bc
使用 FSM 設計組件能夠
關注查看更多原創內容
關注公衆號投遞簡歷 (招聘視覺、交互、前端)