基于单向数据流的 JavaScript 流程管理机制
在 JavaScript 中,变量所对应的值,可以在函数之间传入与返回。
varadd=function(num){returnnum+1}varminus=function(num){returnnum-1}minus(add(add(1)))// => 2对于异步的场景,我们也拥有 es6.promise 可以传递返回值。
varadd=function(num){returnnum+1}varminus=function(num){returnnum-1}Promise.resolve(1).then(add).then(add).then(minus).then(function(value){console.log(value)// => 2})我们完全可以将上述两种技术整合到一起,像下面这样运用:
varadd=function(num){returnnum+1}varminus=function(num){returnnum-1}varasyncAdd=function(num){returnnewPromise(function(resolve){setTimeout(resolve.bind(null,num+1),200)})}vartaskStore={add4: [add,add,add,add,minus,add]//调用5次add,一次minus,使一个数值增加4asyncAdd3: [add,minus,asyncAdd,add,asyncAdd]//异步增值场景}//设想有这种 APIvarprocess=newProcess(taskStore)//像这样传入初始值//同步场景process.resolve('add4',-4)// => 0//异步场景process.resolve('asyncAdd3',-3).then(function(value){console.log(value)// => 0})这样做有几个好处:
数据传递方式更为整洁和直观。像这种
minus(add(add(1)))代码从阅读顺序上,是反直觉的,最先出现的minus实际上最后调用模糊化同步与异步的差别。
asyncAdd后面的add不需要显示地写then函数增强可维护性。修改某个处理环节,能够快速而又明确对应到具体函数;增加某个环节、调整某几个环节的顺序,也非常便利。
就上面显示的情形来说,还有几个问题有待解决。
当 taskHandler 是字符串类型时,跳转到其对应的 taskStore[taskHandler]
vartaskStore={add4: [add,add,add,add,minus,add]//调用5次add,一次minus,使一个数值增加4asyncAdd3: [add,minus,asyncAdd,add,asyncAdd]//异步增值场景asyncAdd7: ['add4','asyncAdd3']//复用 add4 和 asyncAdd3}varprocess=newProcess(taskStore)//异步场景process.resolve('asyncAdd7',-7).then(function(value){console.log(value)// => 0})在 js 中有两个表示空的数据类型,一个是 undefined ,另一个是 null。前者是函数默认返回值,所以我们可以用后者来作为中断传值的标识。
当一个 taskHandler 返回 null 时,后面的 taskHandler 将不会执行。
varprocess=newProcess({add: [function(num){returnnull},function(num){returnnum+1}]})//中断传值都返回 null, 如果是异步的,那么 promise.resolve 的值也是 nullprocess.resolve('add',-1)// => null给 Process 配置 state 属性,所有 taskHandler 接受三个参数: value、state、process
vartaskStore={update: function(value,state,process){state.cache=valueprocess.state===state// true}}varprocess=newProcess(taskStore,{cache: '默认状态'})process.resolve('update','更新状态')process.state.cache// 更新状态加入 taskHandler 是一个具有 goTo 方法的对象,那么将value、state与 process传入其 goTo 方法,该方法返回一个新的 taskHandler,如果这个新的 taskHandler 是函数,则直接执行;是字符串,则跳转;是数组,则循环;还是 goTo 对象,则递归。
如果找不到合法的 taskHandler ,则跳过。
varadd=function(num){returnnum+1}varminus=function(num){returnnum-1}varprocess=newProcess({addToTen: [add,{goTo: function(value,state,process){returnvalue<10 ? 'add' : null}}]})process.resolve('addToTen',-10)// => 10taskStore 中设置一个特殊属性 taskStore.error,它的规则与 taskStore 完全一样,只是调用规则不同。
//寻找 process.store.taskName ,调用它对应的 taskHandler 队列process.resolve(taskName,value)//寻找 process.store.error.errorName,调用它对应的 taskHandler 队列process.reject(errorName,value)process.willResolve(taskName)方法接受一个参数 taskName,返回一个接受 value 的函数,相当于 process.resolve.bind(process, taskName)。
利用这个特性,两个 process 可以嵌套传值。
process1.extend({add: [add,add,process2.willResolve('add3'),process3.willReject('errorName01')]})npm install process-table- CommonJs
varProcess=require('process-table')varadd=function(num){returnnum+1}varprocess=newProcess({add4: [add,add,add,add]})process.resolve('add4',0)// => 4- AMD
define(['process'],function(Process){varadd=function(num){returnnum+1}varprocess=newProcess({add4: [add,add,add,add]})process.resolve('add4',0)// => 4})- script
<scriptsrc="process.js"></script><sciprt> var process = new Process({add: function(num){return num + 1 } }) process.resolve('add', 9) // => 10 <script>taskStore 是一个 key-value 对象,其 key 为 taskName,其 value 为 taskHandler。
taskHandler 可以是函数、字符串、数组、thanable 对象以及具有 goTo 方法的普通对象。
vartaskStore={showState: function(value,state,process){console.log(state)returnvalue},add: function(num,state){returnnum+1},minus: function(num){returnnum-1},add0: ['add','minus']//task 允许数组、字符串、对象addToTen: {goTo: function(value){returnvalue<10 ? 'add' : null}},error: {404: function(value){console.log(value,404)}}}varprocess=newProcess(taskStore,{test: 'initial state'})process.resolve('minus',10)// => 9process.reject('404','test')// test 404 将 sources 合并到 process.store 属性中,返回 store
让 value 值在 taskName 所对应的 taskHandler 队列中传递,如果 taskHandler 全部是同步的,则返回最终的值。如果 taskHandler 队列中存在异步处理器,则返回 promise 对象。
让 value 值在 errorName 对应的 errorHandler 队列中传递,返回值同 Process#resolve 方法。
Process#resolve 的科里化函数,返回接受 value 参数的函数。
Process#reject 的科里化函数,返回接受 value 参数的函数。