兩分鐘搞懂從函數組合到中間件實現

不少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)()
複製代碼
相關文章
相關標籤/搜索