1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        express, koa, redux三者中間件簡單對比分析

        共 6117字,需瀏覽 13分鐘

         ·

        2021-03-19 11:42

        Author: AddOneG

        Link: http://yoursite.com/2018/09/14/express-koa-redux三者中間件對比/


        這三者對各自的中間件有著不同的實現(xiàn),作者本人對此也比較好奇,在這里小小的研究一下源碼,探究三者之間的異同

        什么是中間件

        在我看來,中間件就是在你的代碼運行中進行一些修改的工具。比如你想喝水,那么喝水之前你將水凈化就可以理解為是一次中間件的執(zhí)行。他不是插件,獨立于程序之外,而更像是在你的代碼中表現(xiàn)一種類似連接的功能

        Koa 與 Express 中間件概述

        這兩者都是Node層面的,這里我們根據(jù)官方文檔來對比

        Express

        var app = express();

        // 沒有掛載路徑的中間件,應(yīng)用的每個請求都會執(zhí)行該中間件
        app.use(function (req, res, next{
          console.log('Time:'Date.now());
          next();
        });

        // 掛載至 /user/:id 的中間件,任何指向 /user/:id 的請求都會執(zhí)行它
        app.use('/user/:id'function (req, res, next{
          console.log('Request Type:', req.method);
          next();
        });

        // 路由和句柄函數(shù)(中間件系統(tǒng)),處理指向 /user/:id 的 GET 請求
        app.get('/user/:id'function (req, res, next{
          res.send('USER');
        });

        可以看到express的中間件是使用next進行線性調(diào)用的,一個接著一個的執(zhí)行,是一種尾遞歸的調(diào)用(后文會講)。然后在最后一個中間件中進行對response的處理(習(xí)慣)

        Koa

        const Koa = require('koa');
        const app = new Koa();

        // x-response-time

        app.use(async (ctx, next) => {
          const start = Date.now();
          await next();
          const ms = Date.now() - start;
          ctx.set('X-Response-Time'`${ms}ms`);
        });

        // logger

        app.use(async (ctx, next) => {
          const start = Date.now();
          await next();
          const ms = Date.now() - start;
          console.log(`${ctx.method} ${ctx.url} - ${ms}`);
        });

        // response

        app.use(async ctx => {
          ctx.body = 'Hello World';
        });

        app.listen(3000);

        從代碼中的await可以看出,koa的中間件絕對不是線性的,因為一旦使用了await,代碼就會停止當前中間件的執(zhí)行轉(zhuǎn)而去執(zhí)行await后面的代碼,這里next表示下一個中間件。所以這是一個支持generator的洋蔥圈模型(后文會講)

        Koa 與 Express 中間件源碼進一步解析

        上面提到,express的中間件是尾遞歸調(diào)用,而koa的中間件因為使用了await所以是支持generator的洋蔥圈模型,這里以此展開來分析代碼

        Express

        我們直接進入application.js中觀察中間件處理

        app.handle = function(req, res, callback{
          var stack = this.stack;
          var idx = 0;
          function next(err{
            if (idx >= stack.length) {
              callback('err'
              return;
            }
            var mid;
            while(idx < stack.length) {
              mid = stack[idx++];
              mid(req, res, next);
            }
          }
          next()
        }

        這里next方法不斷取出stack中的中間件并且將自己傳遞給中間件作為參數(shù),這樣中間件只需要調(diào)用next方法就能不斷傳遞到下一個中間件。在函數(shù)的末尾遞歸調(diào)用了next方法,所以稱為尾遞歸調(diào)用

        Koa

        Koa對中間件的處理是在一個獨立的包koa-compose中

        'use strict'

        module.exports = compose

        function compose (middleware{

          return function (context, next{
            let index = -1
            return dispatch(0)
            function dispatch (i{
              index = i
              let fn = middleware[i]
              if (i === middleware.length) fn = next
              if (!fn) return Promise.resolve()
              try {
                return Promise.resolve(fn(context, dispatch.bind(null, i + 1)));
              } catch (err) {
                return Promise.reject(err)
              }
            }
          }
        }

        Koa中使用了Promise來支持異步,這里不停調(diào)用dispatch.bind(null, i + 1)傳遞下一個中間件,一個一個中間件向里執(zhí)行,直到最后一個中間件執(zhí)行完resolve掉,然后不斷向前resolve中間件,直到第一個中間件被resolve。我們可以發(fā)現(xiàn),相應(yīng)的處理并不在中間件中而是在其resolve后

        Redux

        對于redux的基礎(chǔ)createStore,reducer,dispatch等就不解釋了,這> 里直接看applyMiddleware的代碼

        import compose from './compose'

        export default function applyMiddleware(...middlewares{
          return createStore => (...args) => {
            const store = createStore(...args)
            let dispatch = () => {
              throw new Error(
                `Dispatching while constructing your middleware is not allowed. ` +
                  `Other middleware would not be applied to this dispatch.`
              )
            }

            const middlewareAPI = {
              getState: store.getState,
              dispatch(...args) => dispatch(...args)
            }
            const chain = middlewares.map(middleware => middleware(middlewareAPI))
            dispatch = compose(...chain)(store.dispatch)

            return {
              ...store,
              dispatch
            }
          }
        }

        這里還是比較好理解的,middlewareAPI中包含兩個api,一個是store的getState;另一個是覆寫的dispath,這是一個外部變量,最終指向覆寫后的dispach,對于compose的作用是compose(f, g, h) 返回 () => f(g(h(..args)))

        那么dispatch = compose(...chain)(store.dispatch)即原生的 store.dispatch 傳入最后一個“中間件”,返回一個新的dispatch ``, 再向外傳遞到前一個中間件,直至返回最終的dispatch`, 當覆寫后的dispatch調(diào)用時,每個“中間件“的執(zhí)行又是從外向內(nèi)的”洋蔥圈“模型

        ??愛心三連擊

        1.看到這里了就點個在看支持下吧,你的點贊,在看是我創(chuàng)作的動力。

        2.關(guān)注公眾號程序員成長指北,回復(fù)「1」加入高級前端交流群!「在這里有好多 前端 開發(fā)者,會討論 前端 Node 知識,互相學(xué)習(xí)」!

        3.也可添加微信【ikoala520】,一起成長。

        “在看轉(zhuǎn)發(fā)”是最大的支持

        瀏覽 33
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            日本中文在线 | 欧美淫荡熟女 | 久久激情视频 | 91 无套直看片红桃 | 女人g点按摩喷水高潮视频 | 狠狠躁夜夜躁XXXXAAAA | 亚洲嗯啊| 男生女生搞逼 | 欧美成人三级在线播放 | 九九玖玖|