前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >express, koa, redux三者中间件简单对比分析

express, koa, redux三者中间件简单对比分析

作者头像
coder_koala
发布2021-03-27 18:00:09
3950
发布2021-03-27 18:00:09
举报

Author: AddOneG

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

这三者对各自的中间件有着不同的实现,作者本人对此也比较好奇,在这里小小的研究一下源码,探究三者之间的异同

什么是中间件

在我看来,中间件就是在你的代码运行中进行一些修改的工具。比如你想喝水,那么喝水之前你将水净化就可以理解为是一次中间件的执行。他不是插件,独立于程序之外,而更像是在你的代码中表现一种类似连接的功能

Koa 与 Express 中间件概述

这两者都是Node层面的,这里我们根据官方文档来对比

Express

代码语言:javascript
复制
var app = express();

// 没有挂载路径的中间件,应用的每个请求都会执行该中间件
app.use(function (req, res, next) {
  console.log('Time:', Date.now());
  next();
});

// 挂载至 /user/:id 的中间件,任何指向 /user/:id 的请求都会执行它
app.use('/user/:id', function (req, res, next) {
  console.log('Request Type:', req.method);
  next();
});

// 路由和句柄函数(中间件系统),处理指向 /user/:id 的 GET 请求
app.get('/user/:id', function (req, res, next) {
  res.send('USER');
});

可以看到express的中间件是使用next进行线性调用的,一个接着一个的执行,是一种尾递归的调用(后文会讲)。然后在最后一个中间件中进行对response的处理(习惯)

Koa

代码语言:javascript
复制
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,代码就会停止当前中间件的执行转而去执行await后面的代码,这里next表示下一个中间件。所以这是一个支持generator的洋葱圈模型(后文会讲)

Koa 与 Express 中间件源码进一步解析

上面提到,express的中间件是尾递归调用,而koa的中间件因为使用了await所以是支持generator的洋葱圈模型,这里以此展开来分析代码

Express

我们直接进入application.js中观察中间件处理

代码语言:javascript
复制
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中的中间件并且将自己传递给中间件作为参数,这样中间件只需要调用next方法就能不断传递到下一个中间件。在函数的末尾递归调用了next方法,所以称为尾递归调用

Koa

Koa对中间件的处理是在一个独立的包koa-compose中

代码语言:javascript
复制
'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来支持异步,这里不停调用dispatch.bind(null, i + 1)传递下一个中间件,一个一个中间件向里执行,直到最后一个中间件执行完resolve掉,然后不断向前resolve中间件,直到第一个中间件被resolve。我们可以发现,相应的处理并不在中间件中而是在其resolve后

Redux

对于redux的基础createStore,reducer,dispatch等就不解释了,这> 里直接看applyMiddleware的代码

代码语言:javascript
复制
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调用时,每个“中间件“的执行又是从外向内的”洋葱圈“模型

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-03-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 程序员成长指北 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 什么是中间件
  • Koa 与 Express 中间件概述
  • Express
  • Koa
  • Koa 与 Express 中间件源码进一步解析
    • Express
      • Koa
      • Redux
      相关产品与服务
      消息队列 TDMQ
      消息队列 TDMQ (Tencent Distributed Message Queue)是腾讯基于 Apache Pulsar 自研的一个云原生消息中间件系列,其中包含兼容Pulsar、RabbitMQ、RocketMQ 等协议的消息队列子产品,得益于其底层计算与存储分离的架构,TDMQ 具备良好的弹性伸缩以及故障恢复能力。
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档