国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

前端中的中間件

appetizerio / 2038人閱讀

摘要:場景現(xiàn)有函數(shù),要求在不改寫函數(shù)的基礎(chǔ)上,在執(zhí)行該函數(shù)之前添加檢查,檢查返回,再執(zhí)行我們大都會(huì)這樣寫很明顯,這樣的很不靈活如果現(xiàn)在又有,同樣需要在執(zhí)行之前進(jìn)行檢查,再寫一個(gè)嗎不,修改函數(shù)滑水的日子木有幾天,又出現(xiàn)了新的需求,在之前,還有一步操

場景
function stepOne(msg) {
    console.log(msg)
}

function checkStepOne(msg) {
    console.log(`check:${msg}`)
    return msg === "success" ? true : false
}

現(xiàn)有函數(shù) stepOne(),要求在不改寫函數(shù)的基礎(chǔ)上,在執(zhí)行該函數(shù)之前添加檢查 checkStepOne(),

檢查返回 ture,再執(zhí)行 stepOne()

我們大都會(huì)這樣寫

function flow(msg){
    if(checkStepOne(msg)){
        return stepOne(msg)
    }
    return false
}

很明顯,這樣的 flow() 很不靈活

如果現(xiàn)在又有 stepTwo(),同樣需要在執(zhí)行之前進(jìn)行檢查 checkStepTwo(),再寫一個(gè)flowTwo() 嗎?

不,修改函數(shù) flow()

function flow(fn, checkFn, msg) {
    if (checkFn(msg)) {
        return fn(msg)
    }
    return false
}

flow(stepOne, checkStepOne, "success")
flow(stepTwo, checkStepTwo, "success")

滑水的日子木有幾天,又出現(xiàn)了新的需求,在 checkStepOne() 之前,還有一步操作,beforeCheckStepOne()

function beforeCheckStepOne(msg) {
    console.log(`beforeCheckStepOne is "${msg}"`)
}

修改函數(shù) flow()

function flow(fns, msg) {
    let current = fns.shift()
    let result
    while (current) {
        result = current(msg)
        if (result === false) {
            return false
        }
        current = fns.shift()
    }
    return result
}

flow([beforeCheckStepOne, checkStepOne, stepOne], "fail")
// beforeCheckStepOne is "fail"
// checkMsg is "fail"

flow(fns, msg) 中 fns 用來存儲(chǔ)要執(zhí)行的步驟,如果上一個(gè)步驟返回 false,就不繼續(xù)下面的步驟了

套路呢?不妨多一些

AOP,Aspect-oriented programming,面向切面編程

改寫Function的原型

Function.prototype.before = function (fn) {
    let rawFn = this
    return function () {
        if (fn.apply(null, arguments) === false) {
            return false
        }
        rawFn.apply(null, arguments)
    }
}

stepOne.before(checkStepOne).before(beforeCheckStepOne)("success")
// beforeCheckStepOne is "success"
// checkMsg is "success"
// success

再換個(gè)花樣

Function.prototype.after = function (fn) {
    let rawFn = this
    return function () {
        if (rawFn.apply(null, arguments) === false) {
            return false
        }
        fn.apply(null, arguments)
    }
}

beforeCheckStepOne.after(checkStepOne).after(stepOne)("success")
// beforeCheckStepOne is "success"
// checkMsg is "success"
// success

OS:這樣寫不會(huì)被人打嗎?不僅改寫了 Function.prototype,看起來還太裝逼

滑水的日子木有幾天,又出現(xiàn)了新的需求,步驟之間能傳遞額外的消息

改造完,如下,多個(gè) context 對象,用于傳遞信息

function stepOne(msg, context) {
    console.log(msg)
    console.log(context.data)
}

function checkStepOne(msg, context) {
    console.log(`checkMsg is "${msg}"`)
    return msg === "success" ? true : false
}

function beforeCheckStepOne(msg, context) {
    console.log(`beforeCheckStepOne is "${msg}"`)
    context.data = "from beforeCheckStepOne"
}

function flow(fns, msg) {
    let currentFn = fns.shift()
    let result
    let context = {}
    while (currentFn) {
        result = currentFn(msg, context)
        if (result === false) {
            return false
        }
        currentFn = fns.shift()
    }
    return result
}

flow([beforeCheckStepOne, checkStepOne, stepOne], "success")
Middle

盜圖自前端開發(fā)中的中間件

function middle1(next) {
    return () => {
        console.log("Enter the middle1")
        next()
        console.log("Exit the middle1")
    }
}

function middle2(next) {
    return () => {
        console.log("Enter the middle2")
        next()
        console.log("Exit the middle2")
    }
}

function middle3(next) {
    return () => {
        console.log("Enter the middle3")
        next()
        console.log("Exit the middle3")
    }
}

function next() {
    console.log("next")
}

middle1(middle2(middle3(next)))()

這還是3個(gè)中間件,調(diào)用起來就如此丑陋了,當(dāng)有更多的中間件該是如何

重寫個(gè)flow()函數(shù)好了

function flow(funcs, rawNext) {
    let next = funcs.pop()
    next = next(rawNext)
    let middle
    while (funcs.length > 0) {
        middle = funcs.pop()
        next = middle(next)
    }
    return next
}

flow([middle1, middle2, middle3], next)()
// Enter the middle1
// Enter the middle2
// Enter the middle3
// next
// Exit the middle3
// Exit the middle2
// Exit the middle1

執(zhí)行 flow() 的過程,就是在拼湊 middle1(middle2(middle3(next))) 的過程

同時(shí),next() 也可以看成是個(gè)中間件

function flow(funcs) {
    let next = funcs.pop()
    while (funcs.length > 0) {
        let middle = funcs.pop()
        next = middle(next)
    }
    return next
}

flow([middle1, middle2, middle3, next])()

沒有定義過多變量的 while,總是可以用 reduceRight 修飾一下

function flow(funcs) {
    return funcs.reduceRight((a, b) => b(a))
}

flow([middle1, middle2, middle3, next])()
瞅瞅 redux中compose.js 是怎么寫的
/**
 * Composes single-argument functions from right to left. The rightmost
 * function can take multiple arguments as it provides the signature for
 * the resulting composite function.
 *
 * @param {...Function} funcs The functions to compose.
 * @returns {Function} A function obtained by composing the argument functions
 * from right to left. For example, compose(f, g, h) is identical to doing
 * (...args) => f(g(h(...args))).
 */

export default function compose(...funcs) {
  if (funcs.length === 0) {
    return arg => arg
  }

  if (funcs.length === 1) {
    return funcs[0]
  }

  return funcs.reduce((a, b) => (...args) => a(b(...args)))
}
舉個(gè)例子,這個(gè) compose 是怎么玩的

如它注釋中所說,compose(f, g, h) is identical to doing (...args) => f(g(h(...args)))

// 輸入16進(jìn)制字符串,返回8位2進(jìn)制字符串
let sixTeenToTen = x => parseInt(x, 16)
let tenToTwo = x => (x).toString(2)
let addZero = x => ("00000000" + x).slice(-8)

let sixTeenToTwo = compose(addZero, tenToTwo, sixTeenToTen)
console.log(sixTeenToTwo("0x62")) // 01100010

當(dāng)然,你也可以這樣寫

let sixTeenToTwo2 = x => ("00000000" + (parseInt(x, 16)).toString(2)).slice(-8)
console.log(sixTeenToTwo2("0x62")) // 01100010

開心就好

Compose & middle

回到之前的middle1,middle2,middle3 函數(shù)那,同時(shí)把next改寫成middle4

function middle1(next) {
    return (a) => {
        console.log("Enter the middle1")
        next(a)
        console.log("Exit the middle1")
    }
}

function middle2(next) {
    return (a) => {
        console.log("Enter the middle2")
        next(a)
        console.log("Exit the middle2")
    }
}

function middle3(next) {
    return (a) => {
        console.log("Enter the middle3")
        next(a)
        console.log("Exit the middle3")
    }
}

function middle4(next) {
    return (a) => {
        console.log(`middle4:${a}`)
    }
}

let middles = compose(middle1, middle2, middle3, middle4)()
middles("msg")
// Enter the middle1
// Enter the middle2
// Enter the middle3
// middle4:msg
// Exit the middle3
// Exit the middle2
// Exit the middle1

值得一提的是,let middles = compose(middle1, middle2, middle3, middle4)() 最后有一組(),調(diào)用函數(shù),相當(dāng)于middle1(middle2(middle3(middle4()))) 給 middle4 傳入空參數(shù)

執(zhí)行 middle4(),返回

(a) => {
    console.log(`middle4:${a}`)
}

這個(gè)函數(shù),作為 next 參數(shù),執(zhí)行 middle3(next),返回

(a) => {
    console.log("Enter the middle3")
    console.log(`middle4:${a}`)
    console.log("Exit the middle3")
}

這個(gè)函數(shù),作為 next 參數(shù),執(zhí)行 middle2(next),返回

(a) => {
     console.log("Enter the middle2")
     console.log("Enter the middle3")
     console.log(`middle4:${a}`)
     console.log("Exit the middle3")
     console.log("Exit the middle2")
}

這個(gè)函數(shù),作為 next 參數(shù),執(zhí)行 middle1(next),返回

(a) => {
     console.log("Enter the middle1")
     console.log("Enter the middle2")
     console.log("Enter the middle3")
     console.log(`middle4:${a}`)
     console.log("Exit the middle3")
     console.log("Exit the middle2")
     console.log("Exit the middle1")
}

所以,最終 middles 就是這樣的

let middles = compose(middle1, middle2, middle3, middle4)()
// 相當(dāng)于
let middles = (a) => {
     console.log("Enter the middle1")
     console.log("Enter the middle2")
     console.log("Enter the middle3")
     console.log(`middle4:${a}`)
     console.log("Exit the middle3")
     console.log("Exit the middle2")
     console.log("Exit the middle1")  
}
高仿express中的use
class Middle {
    constructor() {
        this.funcs = []
    }

    use(fn) {
        this.funcs.push(fn)
        return this
    }

    work() {
        this.funcs.reduceRight((fn1, fn2) => {
            return () => fn2(fn1)
        }, () => {})()
    }

}

function m1(next) {
    console.log("Enter the middle1")
    next()
    console.log("Exit the middle1")
}

function m2(next) {
    console.log("Enter the middle2")
    next()
    console.log("Exit the middle2")
}

function m3(next) {
    console.log("Enter the middle3")
    next()
    console.log("Exit the middle3")
}

function m4(next) {
    console.log("Enter the middle4")
    console.log("Exit the middle4")
}

let m = new Middle()
m.use(m1)
m.use(m2)
m.use(m3)
m.use(m4)
m.work()

來段小插曲

let fns = [m1, m2, m3, m4, m5]
fns.reduceRight((fn1, fn2) => () => fn2(fn1), () => {})()
// 相當(dāng)于
fns.reduceRight((fn1, fn2) => {
    return () => fn2(fn1)
}, () => {})()
// 結(jié)合之前定義的 m1, m2, m3, m4, m5, 得到結(jié)果
// Enter the middle1
// Enter the middle2
// Enter the middle3
// Enter the middle4
// Exit the middle4
// Exit the middle3
// Exit the middle2
// Exit the middle1

其實(shí)那段 reduceRight,本來是寫成 while 的

let fns = [m1, m2, m3, m4, m5]
let next = () => {}
while(fns.length > 0){
    let fn = fns.pop()
    next = () => fn(next)
}
next()
// 一直輸出 Enter the middle1 

所以做了些調(diào)整

let fns = [m1, m2, m3, m4, m5]
let next = () => {}
while (fns.length > 0) {
    let fn = fns.pop()
    next = function (fn, next) {
        return () => fn(next)
    }(fn, next)
}
next()
// 輸出結(jié)果符合預(yù)期

來自網(wǎng)上的套路是這樣的

class Middle {
    constructor() {
        this.funcs = []
        this.middlewares = []
    }

    use(fn) {
        this.funcs.push(fn)
        return this
    }

    next(fn) {
        if (this.middlewares && this.middlewares.length > 0) {
            let ware = this.middlewares.shift()
            ware.call(this, this.next.bind(this))
        }
    }

    work() {
        this.middlewares = this.funcs.map(f => f)
        this.next()
    }
}

感覺大概就是這個(gè)意思

m4 = m4.bind(null, m5)
m3 = m3.bind(null, m4)
m2 = m2.bind(null, m3)
m1 = m1.bind(null, m2)
m1()
// 或者
m1.call(null, m2.bind(null, m3.bind(null, m4.bind(null, m5))))

再啰嗦地解釋下,因?yàn)槲乙婚_始是看半天沒能理解

let m = new Middle()
m.use(m1)
m.use(m2)
m.use(m3)
m.use(m4)
m.use(m5)
m.work()

執(zhí)行 m.work() 后,

執(zhí)行 m.next()

從 m.middlewares 中取出 m1

執(zhí)行 m1.call(m, m.next)

執(zhí)行 m1 函數(shù)體內(nèi)

console.log("Enter the middle1")

然后遇到 next()

實(shí)際上執(zhí)行了 m.next()

從 m.middlewares 中取出 m2

執(zhí)行 m2.call(m, m.next)

執(zhí)行 m2 函數(shù)體內(nèi)

console.log("Enter the middle2")

然后遇到 next()

實(shí)際上執(zhí)行了 m.next()

從 m.middlewares 中取出 m3

執(zhí)行 m3.call(m, m.next)

執(zhí)行 m3 函數(shù)體內(nèi)

console.log("Enter the middle3")

...

直至結(jié)束

共享數(shù)據(jù)
class Middle {
    constructor() {
        this.funcs = []
        this.middlewares = []
        this.options = null
    }

    use(fn) {
        this.funcs.push(fn)
        return this
    }

    next(fn) {
        if (this.middlewares && this.middlewares.length > 0) {
            let ware = this.middlewares.shift()
            ware.call(this, this.options, this.next.bind(this))
        }
    }

    work(options) {
        this.middlewares = this.funcs.map(f => f)
        this.options = options
        this.next()
    }
}

使用樣例

function m1(options, next) {
    console.log("Enter the middle1")
    console.log(options.name)
    next()
    console.log("Exit the middle1")
}

function m2(options, next) {
    options.name = "m2"
    console.log("Enter the middle2")
    console.log(options.name)
    next()
    console.log("Exit the middle2")
}

function m3(options, next) {
    options.name = "m3"
    console.log("Enter the middle3")
    console.log(options.name)
    next()
    console.log("Exit the middle3")
}

function m4(options, next) {
    console.log("Enter the middle4")
    console.log(options.name)
    console.log("Exit the middle4")
}

function m5(options, next) {
    console.log("Enter the middle5")
    next()
    console.log("Exit the middle5")
}

let m = new Middle()
m.use(m1)
m.use(m2)
m.use(m3)
m.use(m4)
m.use(m5)
m.work({
    name: "m"
})

// Enter the middle1
// m
// Enter the middle2
// m2
// Enter the middle3
// m3
// Enter the middle4
// Exit the middle4
// Exit the middle3
// Exit the middle2
// Exit the middle1

同樣功能的代碼

let fns = [m1, m2, m3, m4, m5]
let next = () => {}
let options = {
    name: "m"
}
while (fns.length > 0) {
    let fn = fns.pop()
    next = function (fn, options, next) {
        return () => fn(options, next)
    }(fn, options, next)
}
next()

同樣功能的代碼

let options = {
    name: "m"
}
m4 = m4.bind(null, options, m5)
m3 = m3.bind(null, options, m4)
m2 = m2.bind(null, options, m3)
m1 = m1.bind(null, options, m2)
m1()
// 相當(dāng)于
fns.reduceRight((fn1, fn2) => fn2.bind(null, options, fn1))()

同樣功能的代碼

let options = {
    name: "m"
}

m44 = () => m4(options, m5)
m33 = () => m3(options, m44)
m22 = () => m2(options, m33)
m11 = () => m1(options, m22)
m11()
// 相當(dāng)于
fns.reduceRight((fn1, fn2) => {
    return () => fn2(options, fn1)
}, () => {})()
// 再精煉的話
fns.reduceRight((fn1, fn2) => () => fn2(options, fn1), () => {})()
// 感覺我3min以后就不認(rèn)得自己寫的代碼了

fn.bind(null, args) 和 return () => fn(args) 在一些場合,功能相同

參考資料

編寫可維護(hù)代碼之“中間件模式”

前端開發(fā)中的中間件

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/93652.html

相關(guān)文章

  • 精彩文章賞析 - 收藏集 - 掘金

    摘要:掘金原文地址譯文出自掘金翻譯計(jì)劃譯者請持續(xù)關(guān)注中文維護(hù)鏈接獲取最新內(nèi)容。由于以下的瀏覽器市場份額已逐年下降,所以對于瀏覽器技巧三視覺效果前端掘金揭秘學(xué)習(xí)筆記系列,記錄和分享各種實(shí)用技巧,共同進(jìn)步。 沉浸式學(xué) Git - 前端 - 掘金目錄 設(shè)置 再談設(shè)置 創(chuàng)建項(xiàng)目 檢查狀態(tài) 做更改 暫存更改 暫存與提交 提交更改 更改而非文件 歷史 別名 獲得舊版本 給版本打標(biāo)簽 撤銷本地更改... ...

    godiscoder 評(píng)論0 收藏0
  • FEDAY2016之旅

    摘要:前戲補(bǔ)上參會(huì)的完整記錄,這個(gè)問題從一開始我就是準(zhǔn)備自問自答的,希望可以通過這種形式把大會(huì)的干貨分享給更多人。 showImg(http://7xqy7v.com1.z0.glb.clouddn.com/colorful/blog/feday2.png); 前戲 2016/3/21 補(bǔ)上參會(huì)的完整記錄,這個(gè)問題從一開始我就是準(zhǔn)備自問自答的,希望可以通過這種形式把大會(huì)的干貨分享給更多人。 ...

    red_bricks 評(píng)論0 收藏0
  • 2018大廠高級(jí)前端面試題匯總

    摘要:面試的公司分別是阿里網(wǎng)易滴滴今日頭條有贊挖財(cái)滬江餓了么攜程喜馬拉雅兌吧微醫(yī)寺庫寶寶樹??低暷⒐浇挚峒覙钒俜贮c(diǎn)和海風(fēng)教育。 (關(guān)注福利,關(guān)注本公眾號(hào)回復(fù)[資料]領(lǐng)取優(yōu)質(zhì)前端視頻,包括Vue、React、Node源碼和實(shí)戰(zhàn)、面試指導(dǎo)) 本人于7-8月開始準(zhǔn)備面試,過五關(guān)斬六將,最終抱得網(wǎng)易歸,深深感受到高級(jí)前端面試的套路。以下是自己整理的面試題匯總,不敢藏私,統(tǒng)統(tǒng)貢獻(xiàn)出來。 面試的公司分...

    zzir 評(píng)論0 收藏0
  • 基于 Webpack 4 多入口生成模板用于服務(wù)端渲染的方案及實(shí)戰(zhàn)

    摘要:原作者原鏈接基于多入口生成模板用于服務(wù)端渲染的方案及實(shí)戰(zhàn)法律聲明警告本作品遵循署名非商業(yè)性使用禁止演繹未本地化版本協(xié)議發(fā)布。這是什么背景現(xiàn)代化的前端項(xiàng)目中很多都使用了客戶端渲染的單頁面應(yīng)用。 原作者:@LinuxerPHL原鏈接:基于 Webpack 4 多入口生成模板用于服務(wù)端渲染的方案及實(shí)戰(zhàn) 法律聲明 警告:本作品遵循 署名-非商業(yè)性使用-禁止演繹3.0 未本地化版本(CC BY-...

    big_cat 評(píng)論0 收藏0
  • 基于 Webpack 4 多入口生成模板用于服務(wù)端渲染的方案及實(shí)戰(zhàn)

    摘要:原作者原博文地址基于多入口生成模板用于服務(wù)端渲染的方案及實(shí)戰(zhàn)法律聲明警告本作品遵循署名非商業(yè)性使用禁止演繹未本地化版本協(xié)議發(fā)布。這是什么背景現(xiàn)代化的前端項(xiàng)目中很多都使用了客戶端渲染的單頁面應(yīng)用。 原作者:@LinuxerPHL原博文地址: 基于 Webpack 4 多入口生成模板用于服務(wù)端渲染的方案及實(shí)戰(zhàn) 法律聲明 警告:本作品遵循 署名-非商業(yè)性使用-禁止演繹3.0 未本地化版本(...

    Lavender 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

appetizerio

|高級(jí)講師

TA的文章

閱讀更多
最新活動(dòng)
閱讀需要支付1元查看
<