1. 程式人生 > >一個只有99行代碼的JS流程框架(二)

一個只有99行代碼的JS流程框架(二)

經驗 itl 兩個 ron timeout 當前 str mmu second

歡迎大家關註騰訊雲技術社區-博客園官方主頁,我們將持續在博客園為大家推薦技術精品文章哦~

張鎮圳,騰訊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流程框架(二)