1.同步compose
function add(a, b) {
return a + b
}
function double(a) {
return a * 2
}
function remove(r){
return r-1
}
先看上边的代码, 如果给add函数传递村始参数1,2。 结果返回3, 然后将返回的结果3传递给double函数, double函数再将将返回结果6传递给remove函数。可以得到结果5。 如果用最原始的方法写, 代码如下
let addRes = add(1,2)
let dbRes = double(addRes)
let rmRes = remove(dbRes)
console.log(rmRes) // 5
//或者
remove(double(add(1,2))) // 5
那么能不能把这种通过值与值之前互相传递的函数封装一下, 只传递函数名称和初始值, 就可以得到想要返回的结果呢。 答案是肯定的, 下面是实现的代码
function compose(mid) {
return function (...args) {
let res = mid[0](...args)
for (let i = 1; i < mid.length; i++) {
res = mid[i](res)
}
return res
}
}
const middlewares = [add, double, remove]
let fn = compose(middlewares)
let final = fn(1, 2) // 5
解析: 封装一个compose函数, 参数是包含各个函数名称的数组。 将要传递的初始参数封装在闭包中。通过es6方法
...args
来解构赋值传递的初始参数。 先得到最初的add
函数返回值mid[0](...args)
。然后for循环剩余参数。 因为已经操作过了mid[0]。所以for循环以1开头。 将第一个add函数返回的值res,传递给第二个函数, 并将结果重新赋值为res, 最后返回res。
2. 异步compose
构建一个异步的compose。 根据洋葱圈模型。 下边代码的执行顺序是 fn1, fn2 2秒后打印fn 3, fn2 end, fn1 end
async function fn1(next) {
console.log('fn1');
await next()
console.log('fn1 end');
}
async function fn2(next) {
console.log('fn2');
await delay()
await next()
console.log('fn2 end');
}
async function fn3(next) {
console.log('fn3');
}
function delay() {
return new Promise(resolve => {
setTimeout(() => {
resolve()
}, 2000)
})
}
由于是异步的,所以使用promise来处理异步。 使用递归去调用函数。
function compose(middlewares) {
return function () {
return dispatch(0)
function dispatch(i) {
let fn = middlewares[i]
if (!fn) {
return Promise.resolve()
}
return Promise.resolve(fn(function next() {
return dispatch(i + 1)
}))
}
}
}
const middlewares = [fn1, fn2, fn3]
const finalFn = compose(middlewares)