<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

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

          共 6214字,需瀏覽 13分鐘

           ·

          2021-03-26 08:42

          Author: AddOneG

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


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

          什么是中間件

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

          Koa 與 Express 中間件概述

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

          Express

          var app = express();

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

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

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

          可以看到express的中間件是使用next進(jìn)行線(xiàn)性調(diào)用的,一個(gè)接著一個(gè)的執(zhí)行,是一種尾遞歸的調(diào)用(后文會(huì)講)。然后在最后一個(gè)中間件中進(jìn)行對(duì)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的中間件絕對(duì)不是線(xiàn)性的,因?yàn)橐坏┦褂昧薬wait,代碼就會(huì)停止當(dāng)前中間件的執(zhí)行轉(zhuǎn)而去執(zhí)行await后面的代碼,這里next表示下一個(gè)中間件。所以這是一個(gè)支持generator的洋蔥圈模型(后文會(huì)講)

          Koa 與 Express 中間件源碼進(jìn)一步解析

          上面提到,express的中間件是尾遞歸調(diào)用,而koa的中間件因?yàn)槭褂昧薬wait所以是支持generator的洋蔥圈模型,這里以此展開(kāi)來(lái)分析代碼

          Express

          我們直接進(jìn)入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方法就能不斷傳遞到下一個(gè)中間件。在函數(shù)的末尾遞歸調(diào)用了next方法,所以稱(chēng)為尾遞歸調(diào)用

          Koa

          Koa對(duì)中間件的處理是在一個(gè)獨(dú)立的包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來(lái)支持異步,這里不停調(diào)用dispatch.bind(null, i + 1)傳遞下一個(gè)中間件,一個(gè)一個(gè)中間件向里執(zhí)行,直到最后一個(gè)中間件執(zhí)行完resolve掉,然后不斷向前resolve中間件,直到第一個(gè)中間件被resolve。我們可以發(fā)現(xiàn),相應(yīng)的處理并不在中間件中而是在其resolve后

          Redux

          對(duì)于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中包含兩個(gè)api,一個(gè)是store的getState;另一個(gè)是覆寫(xiě)的dispath,這是一個(gè)外部變量,最終指向覆寫(xiě)后的dispach,對(duì)于compose的作用是compose(f, g, h) 返回 () => f(g(h(..args)))

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

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

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

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

          瀏覽 54
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  三级片日韩在线观看 | 婷婷亚洲噜噜噜噜 | 官网99热精品 | 欧美操在线观看 | 造逼视频 |