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>

        【W(wǎng)eb技術(shù)】904- Express/Koa/Redux三者中間件對比

        共 6214字,需瀏覽 13分鐘

         ·

        2021-03-26 08: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,代碼就會停止當(dāng)前中間件的執(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`, 當(dāng)覆寫后的dispatch調(diào)用時,每個“中間件“的執(zhí)行又是從外向內(nèi)的”洋蔥圈“模型

        1. JavaScript 重溫系列(22篇全)
        2. ECMAScript 重溫系列(10篇全)
        3. JavaScript設(shè)計模式 重溫系列(9篇全)
        4. 正則 / 框架 / 算法等 重溫系列(16篇全)
        5. Webpack4 入門(上)|| Webpack4 入門(下)
        6. MobX 入門(上) ||  MobX 入門(下)
        7. 100+篇原創(chuàng)系列匯總

        回復(fù)“加群”與大佬們一起交流學(xué)習(xí)~

        點擊“閱讀原文”查看 100+ 篇原創(chuàng)文章

        瀏覽 54
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

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

        手機掃一掃分享

        分享
        舉報
        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>
            人人爱人人插 | 免费观看小黄片 | 中文字幕国产一区二区三区 | 黄片网站免费观看 | 性色av无码久久久久久免费大尺度 | 日韩中文字幕熟妇人妻 | 男生和女生叉叉叉 | 自拍偷拍| 三上悠亚被狂c躁到高潮失禁 | 成人尹人网|