欢迎大家关注腾讯云技术社区-博客园官方主页,我们将持续在博客园为大家推荐技术精品文章哦~

张镇圳,腾讯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流程框架 (一)
JavaScriptCore全面解析 (上篇)
JavaScriptCore全面解析 (下篇)


此文已由作者授权腾讯云技术社区发布,转载请注明文章出处
原文链接:https://www.qcloud.com/community/article/318172
获取更多腾讯海量技术实践干货,欢迎大家前往腾讯云技术社区

 

一个只有99行代码的JS流程框架(二)的更多相关文章

  1. 一个只有99行代码的JS流程框架

    张镇圳,腾讯Web前端高级工程师,对内部系统前端建设有多年经验,喜欢钻研捣鼓各种前端组件和框架. 最近一直在想一个问题,如何能让js代码写起来更语义化和更具有可读性. 上周末的时候突发奇想,当代码在运 ...

  2. (转)如何基于FFMPEG和SDL写一个少于1000行代码的视频播放器

    原文地址:http://www.dranger.com/ffmpeg/ FFMPEG是一个很好的库,可以用来创建视频应用或者生成特定的工具.FFMPEG几乎为你把所有的繁重工作都做了,比如解码.编码. ...

  3. 4行代码实现js模板引擎

    在平时编码中,经常要做拼接字符串的工作,如把json数据用HTML展示出来,以往字符串拼接与逻辑混在在一起会让代码晦涩不堪,加大了多人协作与维护的成本.而采用前端模板机制就能很好的解决这个问题. 精妙 ...

  4. 39行代码实现JS HTML模板(轻量+高效+易用)

    otmpl 是一个轻量级前端模版(仅有39行无压缩代码,支持缓存),所用指令仅需[#...#]和{#...#},前者包含需要输出html语句,后者包含js变量. 支持javascript完整语法,你可 ...

  5. 30 行代码实现 JS 中的 MVC

    一连串的名字走马观花式的出现和更迭,它们中一些已经渐渐淡出了大家的视野,一些还在迅速茁壮成长,一些则已经在特定的生态环境中独当一面舍我其谁.但不论如何,MVC已经并将持续深刻地影响前端工程师们的思维方 ...

  6. JS流程控制语句 二选一 (if...else语句) 语法: if(条件) { 条件成立时执行的代码} else {条件不成立时执行的代码}

    二选一 (if...else语句) if...else语句是在指定的条件成立时执行代码,在条件不成立时执行else后的代码. 语法: if(条件) { 条件成立时执行的代码} else {条件不成立时 ...

  7. 基本上,把switch,用设计模式代替,肯定是bug和过度设计。想想,本来修改一个文件几行代码可以解决的问题,变成修改3-6个类才能实现一样的功能。不是傻是什么?

    那些迷信设计模式的人,来修改一下这个方法吧.看看你最终的代码膨胀为几倍... public virtual PasswordChangeResult ChangePassword(ChangePass ...

  8. 一个几百行代码实现的http服务器tinyhttpd

    /* J. David's webserver */ /* This is a simple webserver. * Created November 1999 by J. David Blacks ...

  9. 30行代码实现js原生三级联动菜单

    var oneArr=[['00','成都'],['01','绵阳'],['02','南充']] var towArr={ '00':[['000','武侯区'],['002','锦江区']], '0 ...

随机推荐

  1. 3314: [Usaco2013 Nov]Crowded Cows

    3314: [Usaco2013 Nov]Crowded Cows Time Limit: 1 Sec  Memory Limit: 128 MBSubmit: 111  Solved: 79[Sub ...

  2. Java 开机启动

    1.授权: <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED">< ...

  3. 利用Arcgis for javascript API绘制GeoJSON并同时弹出多个Popup

    1.引言 由于Arcgis for javascript API不可以绘制Geojson,并且提供的Popup一般只可以弹出一个,在很多专题图制作中,会遇到不少的麻烦.因此本文结合了两个现有的Arcg ...

  4. 谷歌开源图片压缩算法Guetzli实测体验报告

    谷歌大神又出开源新技术啦,这次是对JPEG格式的图片采用全新算法重新编码,输出的图片还是JPEG但是图片大小明显缩小,而质量不但没有损失,甚至还更加优化,速速来体验一把. 一.环境安装 下载谷歌开源软 ...

  5. Android自学反思总结(下)

    后来陆陆续续过了大半个月,导员给找了一个Udacity在线学习的Android开发教程,只有一个月的免费学习机会,因此很快开始了叫Sunshine的天气应用的开发,教学视频整体是采用先自己思考并填写某 ...

  6. rem 结合 scss 移动端自适应 初级入门demo

    首先说明 本篇 内容 适合初级使用 rem 开发移动端 自适应 公式计算 推导过程, 高手绕路. 目标尺寸 = rem  *  根字体大小 Px   =  rem * (html根字体px) 根字体大 ...

  7. 数据库dbutils

    common-dbutils.jarQueryRunnerupdate方法:* int update(String sql, Object... params) -->  可执行增.删.改语句* ...

  8. XJOI1571爱心蜗牛【树形动规】

    爱心蜗牛 猫猫把嘴伸进池子里,正准备"吸"鱼吃,却听到门铃响了.猫猫擦了擦脸上的水,打开门一看,那人正是她的好朋友--川川.川川手里拿着一辆玩具汽车,对猫猫说:"这是我的 ...

  9. poj 3070 Fibonacci (矩阵快速幂乘/模板)

    题意:给你一个n,输出Fibonacci (n)%10000的结果 思路:裸矩阵快速幂乘,直接套模板 代码: #include <cstdio> #include <cstring& ...

  10. 1164: 零起点学算法71——C语言合法标识符(存在问题)

    1164: 零起点学算法71——C语言合法标识符 Time Limit: 1 Sec  Memory Limit: 64 MB   64bit IO Format: %lldSubmitted: 10 ...