一個只有99行代碼的JS流程框架(二)
歡迎大家關註騰訊雲技術社區-博客園官方主頁,我們將持續在博客園為大家推薦技術精品文章哦~
張鎮圳,騰訊Web前端高級工程師,對內部系統前端建設有多年經驗,喜歡鉆研搗鼓各種前端組件和框架。
導語
前面寫了一篇文章,叫《一個只有99行代碼的JS流程框架》,雖然該框架基本已經能實現一個流程正常的邏輯流轉,但是在分模塊應用下還是缺少一定的能力,無法將一個頁面中的不同模塊很好的連接在一起,於是對之前的框架進行了升級,新增了子流程的概念。
子流程
什麽是子流程?在這個升級後的框架裏(當然代碼已經不止99行了,不要在乎標題),每個步驟不但可以是一個function,還可以引用另一個流程,這個被引用的流程就叫子流程。先看個簡單的例子:
flowJS({ init:function(){ this.setNext(‘步驟A‘).setNext(‘步驟B‘).setNext(‘步驟C‘); this.next(); }, ‘步驟A‘:function(){ this.next(); }, ‘步驟B‘:{ init:function(){ this.setNext(‘子步驟B1‘).setNext(‘子步驟B2‘).setNext(‘子步驟B3‘); this.next(); }, ‘子步驟B1‘:function(){ this.next(); }, ‘子步驟B2‘:function(){ this.next(); }, ‘子步驟B3‘:function(){ this.parent.next(); } }, ‘步驟C‘:function(){ console.log(‘執行 步驟C‘); console.log(‘當前流程運行的軌跡:‘); console.log(flowJS.trace); } });
上面這個例子中,步驟B對應的對象就是子流程。
還可以有另一種寫法,也是對分模塊應用的更好的實現:
/*定義子流程*/ flowJS(‘子流程B‘, { init:function(){ this.setNext(‘子步驟B1‘).setNext(‘子步驟B2‘).setNext(‘子步驟B3‘); this.next(); }, ‘子步驟B1‘:function(){ this.next(); }, ‘子步驟B2‘:function(){ this.next(); }, ‘子步驟B3‘:function(){ this.parent.next(); } }); /*父流程*/ flowJS({ init:function(){ this.setNext(‘步驟A‘).setNext(‘步驟B‘).setNext(‘步驟C‘); this.next(); }, ‘步驟A‘:function(){ this.next(); }, ‘步驟B‘:‘子流程B‘, ‘步驟C‘:function(){ console.log(‘執行 步驟C‘); console.log(‘當前流程運行的軌跡:‘); console.log(flowJS.trace); } });
可以看到,父流程的 步驟B 引用了前面定義的 子流程B,這樣對於一些公共的流程邏輯就可以單獨抽取出去作為子流程,被其他父流程引用。而子流程與父流程的交互,我們可以在代碼中通過 this.parent 來實現。
在子流程的每一步中都可以獲取 this.parent,得到的是當前子流程對應的步驟,這個步驟跟其他步驟一樣也具有同樣的API(詳見上一篇文章《一個只有99行代碼的JS流程框架》對步驟API的介紹)。
另外,需要說明的一點:這次的升級,並沒有對流程步驟的API做改變,僅僅是引入了子流程的使用方式,其實就是定義子流程,然後引用子流程,接著就是父流程和子流程之間的交互。
同樣,按照規矩,貼上code(例子的序號接上前篇文章的序號,從10開始)
最簡單的子流程使用方法
flowJS({ init:function(){ console.log(‘執行 init‘); this.setNext(‘步驟A‘).setNext(‘步驟B‘).setNext(‘步驟C‘); this.next(); }, ‘步驟A‘:function(){ console.log(‘執行 步驟A‘); this.next(); }, ‘步驟B‘:{ init:function(){ console.log(‘執行 子步驟B init‘); this.setNext(‘子步驟B1‘).setNext(‘子步驟B2‘).setNext(‘子步驟B3‘); this.next(); }, ‘子步驟B1‘:function(){ console.log(‘執行 子步驟B1‘); this.next(); }, ‘子步驟B2‘:function(){ console.log(‘執行 子步驟B2‘); console.log(‘上一步 :‘+this.getPrev()); //打印:子步驟B1 console.log(‘當前步 :‘+this.getCurr()); //打印:子步驟B2 console.log(‘下一步 :‘+this.getNext()); //打印:子步驟B3 this.next(); }, ‘子步驟B3‘:function(){ console.log(‘執行 子步驟B3‘); this.parent.next(); } }, ‘步驟C‘:function(){ console.log(‘執行 步驟C‘); console.log(‘當前流程運行的軌跡:‘); console.log(flowJS.trace); } });
執行結果:
子流程和父流程 通過 this.parent 進行交互
flowJS({ init:function(){ console.log(‘執行 init‘); this.setNext(‘步驟A‘).setNext(‘步驟B‘).setNext(‘步驟C‘); this.next(); }, ‘步驟A‘:function(){ console.log(‘執行 步驟A‘); this.nextData({name1:‘value1‘}); this.flowData({name2:‘value2‘}); this.next(); }, ‘步驟B‘:{ init:function(){ console.log(‘執行 子步驟B init‘); this.setNext(‘子步驟B1‘).setNext(‘子步驟B2‘).setNext(‘子步驟B3‘); this.next(); }, ‘子步驟B1‘:function(){ console.log(‘執行 子步驟B1‘); this.nextData({name3:‘value3‘}); this.flowData({name4:‘value4‘}); this.next(); }, ‘子步驟B2‘:function(){ console.log(‘執行 子步驟B2‘); console.log(‘父步驟的上一步 :‘+this.parent.getPrev());//打印:步驟A console.log(‘父步驟的步驟名 :‘+this.parent.getCurr());//打印:步驟B console.log(‘父步驟的下一步 :‘+this.parent.getNext());//打印:步驟C console.log(‘父步驟的數據:‘); console.log(this.parent.stepData());//打印:Object {name1: "value1"} console.log(this.parent.flowData());//打印:Object {name2: "value2"} console.log(‘上一步 :‘+this.getPrev());//打印:子步驟B1 console.log(‘當前步 :‘+this.getCurr());//打印:子步驟B2 console.log(‘下一步 :‘+this.getNext());//打印:子步驟B3 console.log(‘當前步的數據:‘); console.log(this.stepData());//打印:Object {name3: "value3"} console.log(this.flowData());//打印:Object {name4: "value4"} this.next(); }, ‘子步驟B3‘:function(){ console.log(‘執行 子步驟B3‘); this.parent.nextData({name5:‘value5‘}); this.parent.flowData({name6:‘value6‘}); this.parent.next(); } }, ‘步驟C‘:function(){ console.log(‘執行 步驟C‘); console.log(this.stepData());//打印:Object {name5: "value5"} console.log(this.flowData());//打印:Object {name2: "value2", name6: "value6"} console.log(‘當前流程運行的軌跡:‘); console.log(flowJS.trace); } });
執行結果:
多個子流程並行執行
flowJS({ init:function(){ console.log(‘執行 init‘); this.setNext(‘步驟A‘).setNext([‘步驟B‘, ‘步驟C‘]).setNext(‘步驟D‘); this.next(); }, ‘步驟A‘:function(){ console.log(‘執行 步驟A‘); this.next(); }, ‘步驟B‘:{ init:function(){ console.log(‘執行 子步驟B init‘); this.setNext(‘子步驟B1‘).setNext(‘子步驟B2‘).setNext(‘子步驟B3‘); this.next(); }, ‘子步驟B1‘:function(){ console.log(‘執行 子步驟B1‘); this.next(); }, ‘子步驟B2‘:function(){ console.log(‘執行 子步驟B2‘); this.next(); }, ‘子步驟B3‘:function(){ var self = this; //這裏打印的時間和 子步驟C3 的時間一樣 console.log(‘執行 子步驟B3 時間:‘ + new Date().getSeconds()); setTimeout(function(){ self.parent.next(); }, 2000); } }, ‘步驟C‘:{ init:function(){ console.log(‘執行 子步驟C init‘); this.setNext(‘子步驟C1‘).setNext(‘子步驟C2‘).setNext(‘子步驟C3‘); this.next(); }, ‘子步驟C1‘:function(){ console.log(‘執行 子步驟C1‘); this.next(); }, ‘子步驟C2‘:function(){ console.log(‘執行 子步驟C2‘); this.next(); }, ‘子步驟C3‘:function(){ var self = this; //這裏打印的時間和 子步驟B3 的時間一樣 console.log(‘執行 子步驟C3 時間:‘ + new Date().getSeconds()); setTimeout(function(){ self.parent.next(); }, 2000); } }, ‘步驟D‘:function(){ //這裏打印的時間比上面的子流程的時間晚2秒,因為兩個子流程是並行執行的 console.log(‘執行 步驟D 時間:‘ + new Date().getSeconds()); console.log(‘當前流程運行的軌跡:‘); console.log(flowJS.trace); } });
執行結果:
定義子流程和引用子流程
flowJS(‘子流程A‘, { init:function(){ this.next(‘子步驟A1‘); }, ‘子步驟A1‘:function(){ console.log(‘執行 子步驟A1‘); console.log(‘當前步驟:‘+this.getCurr());//打印:子步驟A1 console.log(‘父步驟:‘+this.parent.getCurr());//打印:步驟A this.parent.next(); } }); flowJS(‘子流程B‘, { init:function(){ console.log(‘執行 子步驟B init‘); this.setNext(‘子步驟B1‘).setNext(‘子步驟B2‘).setNext(‘子步驟B3‘); this.next(); }, ‘子步驟B1‘:function(){ console.log(‘執行 子步驟B1‘); this.next(); }, ‘子步驟B2‘:function(){ console.log(‘執行 子步驟B2‘); this.next(); }, ‘子步驟B3‘:function(){ console.log(‘執行 子步驟B3‘); console.log(‘當前步驟:‘+this.getCurr());//打印:子步驟B3 console.log(‘父步驟:‘+this.parent.getCurr());//打印:步驟B this.parent.next(); } }); flowJS(‘子流程C‘, { init:function(){ console.log(‘執行 子步驟C init‘); this.setNext(‘子步驟C1‘).setNext(‘子步驟C2‘).setNext(‘子步驟C3‘); this.next(); }, ‘子步驟C1‘:function(){ console.log(‘執行 子步驟C1‘); this.next(); }, ‘子步驟C2‘:function(){ console.log(‘執行 子步驟C2‘); this.next(); }, ‘子步驟C3‘:function(){ console.log(‘執行 子步驟C3‘); console.log(‘當前步驟:‘+this.getCurr());//打印:子步驟C3 console.log(‘父步驟:‘+this.parent.getCurr());//打印:步驟C this.parent.next(); } }); flowJS({ init:function(){ console.log(‘執行 init‘); this.setNext(‘步驟A‘).setNext([‘步驟B‘, ‘步驟C‘]).setNext(‘步驟D‘); this.next(); }, ‘步驟A‘:‘子流程A‘, ‘步驟B‘:‘子流程B‘, ‘步驟C‘:‘子流程C‘, ‘步驟D‘:function(){ console.log(‘當前流程運行的軌跡:‘); console.log(flowJS.trace); } });
執行結果:
從上面幾個例子可以看到,子流程和父流程之間的信息交互非常簡單,其實就是通過this.parent來獲取到父步驟,通過父步驟來獲取和傳遞數據,因此也能讓這個流程框架擁有更大能力來適應更多的應用場景。
為了方便交流學習,上面例子完整代碼可通過附件下載,最後同樣貼上框架源碼:
相關閱讀
一個只有99行代碼的JS流程框架(二)