两分钟搞懂从函数组合到中间件实现

不少JS框架中都会用到中间件,造成一个洋葱圈结构,这样能够很好的应付业务逻辑中的对于切面描述的须要。 经典案例好比Redux 中间件和Koa 中间件数组

1.无组合状态

async function fn1(next){
    console.log('fn1')
    console.log('end fn1')
}

async function fn2(next){
    console.log('fn2')
    console.log('end fn2')
}

function fn3(next){
    console.log('fn3')
}

fn3(fn2(fn1()))
复制代码

这个其实不能叫作组合 只是程序先运行最内层的表达式 而后向外运行 实际上这个执行顺序就是 fn1 -> fn2 -> fn3 执行结果以下:bash

fn1
end fn1
fn2
end fn2
fn3
复制代码

固然这个里面你即便写await执行顺序也没有什么变化框架

(async () => {
    await fn3(await fn2(await fn1()))
})()
复制代码

2.两个函数的组合

下面咱们经过参数传递的方式把两个函数组合成一个函数。异步

async function fn1(next){
    console.log('fn1')
    next && await next()
    console.log('end fn1')
}

async function fn2(next){
    console.log('fn2')
    next && await next()
    console.log('end fn2')
}

fn2(fn1)
复制代码

执行结果以下async

fn2
fn1
end fn1
end fn2
复制代码

3 多个函数的组合

影响多个函数不能串行的缘由是 fn2的中不能返回函数结果。 解决这个问题的方法是不要函数的运行结果而是将函数科里化后返回函数

async function fn1(next){
    console.log('fn1')
    next && await next()
    console.log('end fn1')
}

async function fn2(next){
    console.log('fn2')
    next && await next()
    console.log('end fn2')
}
async function fn3(next){
    console.log('fn3')
    next && await next()
    console.log('fn3')
}

async function fn4(next){
    console.log('fn4')
    next && await next()
    console.log('fn4')
}
fn1(() => fn2(() => fn3(fn4)))
复制代码

看一下执行结果ui

fn1
fn2
fn3
fn4
fn4
fn3
end fn2
end fn1
复制代码

4.通用异步Compose函数

最后咱们将这个操做写成一个通用函数spa

const compose = (...args) =>  {
    [first,...others] = args.reverse()
    let ret = first
    others.forEach(fn => {
        let retOld = ret
        ret = () => fn(retOld)
    })
    return ret
}

compose(fn1,fn2,fn3,fn4)()
复制代码
相关文章
相关标签/搜索