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

資訊專(zhuān)欄INFORMATION COLUMN

深度剖析 redux applyMiddleware 中 compose 構(gòu)建異步數(shù)據(jù)流的思路

tinylcy / 1034人閱讀

摘要:前言本文作者站在自己的角度深入淺出算了別這么裝逼分析在設(shè)計(jì)過(guò)程中通過(guò)構(gòu)建異步數(shù)據(jù)流的思路。看上去那是相當(dāng)?shù)耐昝溃鶕?jù)咱們寫(xiě)代碼的思路咱們來(lái)比對(duì)一下原版吧。時(shí)直接返回傳入函數(shù)函數(shù)。

前言
本文作者站在自己的角度深入淺出...算了別這么裝逼分析 redux applyMiddleware 在設(shè)計(jì)過(guò)程中通過(guò) compose 構(gòu)建異步數(shù)據(jù)流的思路。自己假設(shè)的一些場(chǎng)景幫助理解,希望大家在有異步數(shù)據(jù)流并且使用redux的過(guò)程中能夠有自己的思路(脫離thunk or saga)構(gòu)建自己的 enhancer.如果你看完本文之后還想對(duì)我有更多的了解,可以移步我的github;
正文

實(shí)際場(chǎng)景中遇到一個(gè)這樣的問(wèn)題:商品詳情頁(yè)的微信頁(yè)面,未注冊(cè)的用戶(hù)點(diǎn)擊購(gòu)買(mǎi)一個(gè)商品,我們希望能夠?qū)崿F(xiàn)靜默登錄就有如下幾個(gè)步驟:

獲取code;

獲取openId、AccessToken;

根據(jù)openId、獲取openId、AccessToken;獲取用戶(hù)信息實(shí)現(xiàn)自動(dòng)注冊(cè)然后登錄;

跳到商品購(gòu)買(mǎi)頁(yè)。

這是就是一個(gè)典型異步數(shù)據(jù)流的過(guò)程。在上一個(gè)函數(shù)執(zhí)行到某個(gè)時(shí)候再去調(diào)用下一個(gè)函數(shù),使得這些個(gè)函數(shù)能夠順序執(zhí)行。我們簡(jiǎn)化一下,構(gòu)建如下的函數(shù)數(shù)組使得他們能夠順序執(zhí)行吧:

const fucArr = [
    next=>{
        setTimeout(()=>{
              console.log(1);
              next()
        }, 300)
    },
    next=>{
        setTimeout(()=>{
              console.log(2);
              next()
        }, 200)
      },
    next=>{
        setTimeout(()=>{
              console.log(3);
              next()
        }, 100)
    }
]

擼起袖子就開(kāi)始干了起來(lái),有三個(gè)函數(shù),基于走一步看一步思想(瞎胡說(shuō)的)那我就先執(zhí)行兩個(gè)吧

    fucArr[0]( fucArr[1] );// funcArr[1] 運(yùn)行報(bào)錯(cuò) TypeError: next is not a function

報(bào)錯(cuò),因?yàn)?b>fucArr[1]中有next函數(shù)調(diào)用,也得接收一個(gè)函數(shù),這下就麻煩了,fucArr[1]又不能直接傳參調(diào)用(因?yàn)闀?huì)比fucArr[0]先執(zhí)行),于是乎我們需要婉轉(zhuǎn)一點(diǎn)。

    fucArr[0]( ()=>fucArr[1](()=>{}) ); //1 2 
兩個(gè)函數(shù)順序執(zhí)行搞定了那三個(gè)函數(shù)豈不是,沒(méi)錯(cuò),小case。
    fucArr[0]( ()=>fucArr[1](()=>{ fucArr[2](()=>{}) }) );// 1 2 3

那我想在數(shù)組后面再加一個(gè)函數(shù)內(nèi)心os:不加,去死,這樣寫(xiě)下去真是要沒(méi)玩沒(méi)了了;

既然是個(gè)數(shù)組,那咱們就循環(huán)吧,思路肯定是:1.下個(gè)函數(shù)重新整合一下,作為參數(shù)往上一個(gè)函數(shù)傳;2.當(dāng)?shù)奖闅v到數(shù)組末尾的時(shí)候傳入一個(gè)空函數(shù)進(jìn)去避免報(bào)錯(cuò)。

OK開(kāi)始,既然是循環(huán)那就來(lái)個(gè)for循環(huán)吧,既然是下一個(gè)函數(shù)傳給上一個(gè)當(dāng)參數(shù),得讓相鄰的兩個(gè)函數(shù)出現(xiàn)在同一個(gè)循環(huán)里啦。于是有了起手式:

    for (let index = 0; index < fucArr.length; index++) {
        const current = array[index];
        const next = array[index + 1];
        current(()=>next())
    }

起手后發(fā)現(xiàn)不對(duì)呀,我需要喝口熱水,壓壓驚,冷靜一下,仔細(xì)觀察一下上面咱們代碼的結(jié)構(gòu)發(fā)現(xiàn)咱們的函數(shù)結(jié)構(gòu)其實(shí)是醬紫的:

    a(()=>{
        b(c)
    })

實(shí)際就上上一個(gè)函數(shù)調(diào)用被 ()=> 包裹后的下一個(gè)函數(shù)直接調(diào)用并傳入一個(gè)函數(shù)c,而函數(shù)c會(huì)在函數(shù)b的運(yùn)行的某個(gè)時(shí)刻被調(diào)用,并且能接收下一個(gè)函數(shù)作為參數(shù)然后......再說(shuō)下去就沒(méi)玩沒(méi)了了,因此c函數(shù)的模式其實(shí)也是被一個(gè)()=>{}包裹住的函數(shù);然后再觀察我們上面的模式?jīng)]有c傳遞,因此模式應(yīng)該是:

    a(c=>{
        b(c)
    })
    // 我們?cè)偻聦?xiě)一層
    a(
        d=>{
            (
                c=>b(c)
            )(
                d=>c(d)
            )// 為了避免你們看不懂我在寫(xiě)啥,我告訴你你,這玩意兒是函數(shù)自調(diào)用
        }
    )
    // 怎么樣是不是有一種豁然開(kāi)朗的趕腳

我們發(fā)現(xiàn)每次新加入一個(gè)函數(shù),都是重新構(gòu)建一次a函數(shù)里的參數(shù),以下我將這個(gè)參數(shù)簡(jiǎn)稱(chēng)函數(shù)d

于是乎我們來(lái)通過(guò)循環(huán)構(gòu)建這個(gè)d

為了讓循環(huán)體都能拿到d,因此它肯定是在循環(huán)的上層作用域

而且d具有兩個(gè)特性:

能接受一個(gè)函數(shù)作為參數(shù),這個(gè)函數(shù)還能接收另一個(gè)函數(shù)作為參數(shù),并會(huì)在某個(gè)時(shí)刻進(jìn)行調(diào)用

每次循環(huán)都會(huì)根據(jù)當(dāng)前d,然后加入當(dāng)前函數(shù),按照相同模式進(jìn)行重構(gòu);

ps: 我們發(fā)現(xiàn)這兩個(gè)特性其實(shí)和咱們傳入的每個(gè)函數(shù)特性是一致的。

   于是乎咱們把第一個(gè)數(shù)組的函數(shù)組作為起始函數(shù):
    var statusRecord = fucArr[0];
    for (let index = 1; index < fucArr.length; index++) {
        statusRecord = next=>statusRecord(()=>fucArr[index](next))
    }
  寫(xiě)完發(fā)現(xiàn)這樣是錯(cuò)誤的,如果調(diào)用函數(shù)statusRecord那就會(huì)變成,自己調(diào)自己,自己調(diào)自己,自己調(diào)自己,自己調(diào)自己~~皮一下很開(kāi)心~~...的無(wú)限遞歸。
  在循環(huán)記錄當(dāng)前狀態(tài)的場(chǎng)景下,有一個(gè)經(jīng)典的demo大家了解過(guò):在一個(gè)li列表中注冊(cè)點(diǎn)擊事件,點(diǎn)擊后alert出當(dāng)前index;具體就不詳述了于是statusRecord,就改寫(xiě)成了下面這樣
    statusRecord = ((statusRecord)=>(next)=>statusRecord(()=>fucArr[index](next))(statusRecord))
  為什么index不傳呢?因?yàn)閕ndex是let定義,可以看做塊級(jí)作用域,又有人要說(shuō)js沒(méi)有塊級(jí)作用域,我:你說(shuō)得對(duì),再見(jiàn)。
  最后咱們得到的還是這個(gè)模型要調(diào)用,別忘了傳入一個(gè)函數(shù)功最后數(shù)組最后一個(gè)函數(shù)調(diào)用。不然會(huì)報(bào)錯(cuò)
    statusRecord(()=>{}) // 輸出1、2、3
那咱們的功能就此實(shí)現(xiàn)了;不過(guò)可以?xún)?yōu)化一哈。咱們上面的代碼有幾個(gè)要素:

數(shù)組循環(huán)

狀態(tài)傳遞

初始狀態(tài)為數(shù)組的第一個(gè)元素

最終需要拿到單一的返回值

不就是活脫脫用來(lái)描述reduce的嗎?于是乎我們可以這樣擼
    //pre 前一個(gè)狀態(tài)、 cur當(dāng)前循環(huán)函數(shù)、next 待接收的下一個(gè)
      fucArr.reduce((pre, cur)=>{
          return (next)=>pre(()=>cur(next))
      })(()=>{})// 1 2 3
   以上異步順序調(diào)用的問(wèn)題咱們已經(jīng)理解了,咱們依次輸出了1,2,3。但是咱們現(xiàn)實(shí)業(yè)務(wù)中常常是下一個(gè)函數(shù)執(zhí)行,和上一個(gè)函數(shù)執(zhí)行結(jié)果是關(guān)聯(lián)的。咱們就想能不能改動(dòng)題目貼合實(shí)際場(chǎng)景,上一個(gè)函數(shù)告訴下一個(gè)函數(shù)`console.log(n)`,于是乎題目做了一個(gè)小調(diào)整。
    const fucArr = [
        next=>{
            setTimeout(()=>{
                console.log(1);
                next(2)
            }, 300)
        },
        // 函數(shù)2
        (next,n)=>{
        console.log(n);
            next(3)
        },
        // 函數(shù)3
        (next,n)=>{
        console.log(n);
            next(4)
        }
    ]

    fucArr.reduce((pre,cur)=>{
        return (next)=>pre((n)=>cur(next,n))
    })((n)=>{console.log(n)})// 1 2 3 4
   哇,功能又實(shí)現(xiàn)了,我們真棒。現(xiàn)在我們來(lái)回憶一下redux里中間件里傳入函數(shù)格式
store=>next=>action=>{
    // dosomething...
    next()
}
    在某一步中store會(huì)被剝掉,在這就不細(xì)說(shuō)了,于是咱們題目再變個(gè)種
    const fucArr = [
        next=>n=>{
            setTimeout(()=>{
                console.log(n);
                next(n+1)
            }, 300)
        },
        // 函數(shù)2
        next=>n=>{
            setTimeout(()=>{
                console.log(n);
                next(n+1)
            }, 300)
        },
        // 函數(shù)3
        next=>n=>{
            setTimeout(()=>{
                console.log(n);
                next(n+1)
            }, 300)
        }
    ]

臥槽,我們發(fā)現(xiàn)之于之前遇到的問(wèn)題,這個(gè)實(shí)現(xiàn)就舒服很多了。因?yàn)槟銈魅氲暮瘮?shù)應(yīng)該是直接調(diào)用,因?yàn)槲覀冃枰恼{(diào)用的函數(shù)體其實(shí)是傳入函數(shù)調(diào)用后返回的那個(gè)函數(shù),不需要我們通過(guò)()=>{...}這種額外的包裝。
于是咱們的實(shí)現(xiàn)就變成了:

    fucArr.reduce((pre,cur)=>{
        return (next)=>pre(cur(next))
    })((n)=>{console.log(n)})

我們自信滿(mǎn)滿(mǎn)的node xxx.js了一下發(fā)現(xiàn)?????what fuck 為啥什么都沒(méi)有輸出,喝第二口水壓壓驚分析一下:

    // before 之前的第一個(gè)函數(shù)和函數(shù)模型
    next=>{
        setTimeout(()=>{
            console.log(1);
            next(n+1)
        }, 300)
    }
    a(c=>{
        b(c)
    })

    // ------------
    // after 現(xiàn)在的第一個(gè)函數(shù)和函數(shù)模型
    next=>n=>{
        setTimeout(()=>{
            console.log(n);
            next(n+1)
        }, 300)
    }
    a(b(c))
    // 發(fā)現(xiàn)現(xiàn)在的第一個(gè)函數(shù)調(diào)用之后,一個(gè)函數(shù)。這個(gè)函數(shù)還要再接收一個(gè)參數(shù)去啟動(dòng)

(⊙v⊙)嗯沒(méi)錯(cuò),經(jīng)過(guò)精妙的分析我知道要怎么做了。

    fucArr.reduce((pre,cur)=>{
        return (next)=>pre(cur(next))
    })((n)=>{console.log(n)})(1)// 1 2 3 4

我們來(lái)把這個(gè)功能包裝成方法,就叫他compose好了。

    const compose = fucArr=>{
        if(fucArr.length === 0) return;
        if(fucArr.length === 1)    return fucArr[0]((n)=>{console.log(n)})(1)
        fucArr.reduce((pre,cur)=>{
            return (next)=>pre(cur(next))
        })((n)=>{console.log(n)})(1)
    }

看上去那是相當(dāng)?shù)耐昝溃鶕?jù)咱們寫(xiě)代碼的思路咱們來(lái)比對(duì)一下原版吧。

length === 0 時(shí): 返回一個(gè)傳入什么返回什么的函數(shù)。

length === 1 時(shí): 直接返回傳入函數(shù)函數(shù)。

length > 1 時(shí): 構(gòu)建一個(gè)a(b(c(....)))這種函數(shù)調(diào)用模型并返回,使用者自定義最后一環(huán)需要運(yùn)行的函數(shù),并且能夠定義進(jìn)入第一環(huán)的初始參數(shù)

    // 原版
    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)))
    }
結(jié)語(yǔ)
最后說(shuō)一點(diǎn)題外話,在整個(gè)實(shí)現(xiàn)的過(guò)程中確保異步調(diào)用順序還有很多方式。親測(cè)可用的方式有:

bind

遞歸調(diào)用

通過(guò)new Promise 函數(shù),將resolve作為參數(shù)方法傳入上一個(gè)函數(shù)然后改變Promise狀態(tài)...,

如果大家有興趣可以自己實(shí)現(xiàn)一下,為了不把大家的思路帶歪,在寫(xiě)的過(guò)程中并沒(méi)有體現(xiàn)出來(lái)。

感謝@MrTreasure幫我指出文章中的問(wèn)題,如果覺(jué)得我寫(xiě)對(duì)你有一定的幫助,那就點(diǎn)個(gè)贊吧,因?yàn)槟墓膭?lì)是我最大的動(dòng)力。

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

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/100310.html

相關(guān)文章

  • Redux專(zhuān)題:間件

    摘要:好處就是不再需要能夠處理異步的中間件了。不過(guò),它是一個(gè)研究中間件很好的范本。執(zhí)行它,返回的是由第二層函數(shù)組成的中間件數(shù)組。也就是說(shuō)呀同學(xué)們,除了最后一個(gè)中間件的是原始的之外,倒數(shù)往前的中間件傳入的都是上一個(gè)中間件的邏輯函數(shù)。 本文是『horseshoe·Redux專(zhuān)題』系列文章之一,后續(xù)會(huì)有更多專(zhuān)題推出來(lái)我的 GitHub repo 閱讀完整的專(zhuān)題文章來(lái)我的 個(gè)人博客 獲得無(wú)與倫比的閱...

    ybak 評(píng)論0 收藏0
  • redux源碼解讀--applyMiddleware源碼解析

    摘要:的中間件主要是通過(guò)模塊實(shí)現(xiàn)的。返回的也是一個(gè)對(duì)象這個(gè)其實(shí)就是,各個(gè)中間件的最底層第三層的哪個(gè)函數(shù)組成的圓環(huán)函數(shù)構(gòu)成的這就是對(duì)源碼的一個(gè)整體解讀,水平有限,歡迎拍磚。后續(xù)的源碼解讀和測(cè)試?yán)涌梢躁P(guān)注源碼解讀倉(cāng)庫(kù) applyMiddleware源碼解析 中間件機(jī)制在redux中是強(qiáng)大且便捷的,利用redux的中間件我們能夠?qū)崿F(xiàn)日志記錄,異步調(diào)用等多種十分實(shí)用的功能。redux的中間件主要是...

    Atom 評(píng)論0 收藏0
  • redux middleware 詳解

    摘要:執(zhí)行完后,獲得數(shù)組,,它保存的對(duì)象是圖中綠色箭頭指向的匿名函數(shù),因?yàn)殚]包,每個(gè)匿名函數(shù)都可以訪問(wèn)相同的,即。是函數(shù)式編程中的組合,將中的所有匿名函數(shù),,組裝成一個(gè)新的函數(shù),即新的,當(dāng)新執(zhí)行時(shí),,從左到右依次執(zhí)行所以順序很重要。 前言 It provides a third-party extension point between dispatching anaction, and t...

    yanwei 評(píng)論0 收藏0
  • 走近 Redux

    摘要:的核心思想就是維護(hù)一個(gè)單向數(shù)據(jù)流,數(shù)據(jù)的流向永遠(yuǎn)是單向的,所以每個(gè)步驟便是可預(yù)測(cè)的,程序的健壯性得到了保證。另外,還有一點(diǎn)比較重要的是,因?yàn)闆](méi)有了一個(gè)一直保存更新的狀態(tài)對(duì)象,所以在中的也就沒(méi)有意義了,通過(guò)可以完全實(shí)現(xiàn)一個(gè)順暢的數(shù)據(jù)流。 1 Redux Redux is a predictable state container for JavaScript apps 簡(jiǎn)單來(lái)說(shuō),Redu...

    fevin 評(píng)論0 收藏0
  • Redux原理分析

    摘要:調(diào)用鏈中最后一個(gè)會(huì)接受真實(shí)的的方法作為參數(shù),并借此結(jié)束調(diào)用鏈。總結(jié)我們常用的一般是除了和之外的方法,那個(gè)理解明白了,對(duì)于以后出現(xiàn)的問(wèn)題會(huì)有很大幫助,本文只是針對(duì)最基礎(chǔ)的進(jìn)行解析,之后有機(jī)會(huì)繼續(xù)解析對(duì)他的封裝 前言 雖然一直使用redux+react-redux,但是并沒(méi)有真正去講redux最基礎(chǔ)的部分理解透徹,我覺(jué)得理解明白redux會(huì)對(duì)react-redux有一個(gè)透徹的理解。 其實(shí),...

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

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

0條評(píng)論

tinylcy

|高級(jí)講師

TA的文章

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