Express和koa的区别

前言


😳大家好,我是一溪风月程序员界的搬砖工,在Node专栏中我们已经学习过了Expresskoa的基本使用 Express使用的是非常广泛的,包括Nest默认也是依赖Express框架,koa相对于Express比较新,同时从设计层面设计的比较小巧,那么这篇文章我们就来看下Expresskoa框架的区别以及在同步异步时候的差异。

一.架构设计的差异


  1. Express是完整和强大的,其中帮助了我们内置了非常多的好用的功能。
  2. koa是简洁和自由的它只包含最核心的功能,并不会对我们使用其他中间件进行约束。
  3. 因为Express和koa框架的核心都是中间件,但是中间件的执行机制是不同的特别是中间件包含异步操作时候

二.koa中间件的同步操作和异步操作


🐲同步操作:首先我们先搭建一个koa的环境,执行如下命令。

js 复制代码
npm init -y
npm install koa

然后我们直接编写全局中间件来验证同步代码情况下koa中间件是如何进行执行的,代码如下:

js 复制代码
const koa = require('koa')

const app = new koa()


app.use((ctx, next) => {
  console.log("第一个全局中间件")
  ctx.msg = "aaa"
  next()

  // 返回的数据
  ctx.body = ctx.msg
})

app.use((ctx, next) => {
  console.log("第二个中间件")
  ctx.msg += 'bbb'
  next()
})

app.use((ctx, next) => {
  console.log("第三个中间件")
  ctx.msg += 'ccc'
})

app.listen(8000, () => {
  console.log("服务运行在8000端口")
})

我们使用apifox来进行快捷请求,因为是全局中间件所以我们请求就会触发。

然后我们查看返回的数据。

代码中的ctx.msg是我们自己给ctx对象添加的属性内容,koa的中间件会从上到下进行执行,因此从第一个中间件开始进行相加每个中间件代码执行完之后都会调用next来执行下一个中间件,如果我们在其中某个中间件中的next进行注释掉就不会执行下一个中间件,比如我们注释掉第二个。

我们在前端界面上展示的其实是ctx.body的内容,这说明koa的中间件在执行到最后一个中间的时候会依次返回执行其余的代码,我们可以测试一下,我们对代码进行如下改造。

js 复制代码
const koa = require('koa')

const app = new koa()


app.use((ctx, next) => {
  console.log("第一个全局中间件")
  ctx.msg = "aaa"
  next()

  // 返回的数据
  ctx.body = ctx.msg
  console.log("执行完毕返回第一个中间件")
})

app.use((ctx, next) => {
  console.log("第二个中间件")
  ctx.msg += 'bbb'
  next()
  console.log("执行完毕返回第二个中间件")
})

app.use((ctx, next) => {
  console.log("第三个中间件")
  ctx.msg += 'ccc'
})

app.listen(8000, () => {
  console.log("服务运行在8000端口")
})

依然使用apifox进行请求一下,我们看下控制台打印的内容。

执行的顺序就是:第一个中间件-->第二个中间件-->第三个中间件-->返回第二个中间件-->返回第一个中间件

其实这就是所谓的洋葱模型,后续我们再讲解洋葱模型相关内容。

🐸异步操作:上述我们讲解了koa进行同步操作的时候中间件的执行顺序,接下来我们来一起看下当koa执行异步操作的时候中间件的执行顺序是什么样的。

我们首先安装下axios方便来模拟异步请求,同时我们新建一个文件来搭建一个简单的接口服务。

js 复制代码
yarn add axios
js 复制代码
const koa = require('koa')
const app = new koa()

app.use((ctx, next) => {
  ctx.body = {
    name: '王鹏',
    age: 12
  }
})

app.listen(8001, () => {
  console.log("服务运行在8001端口")
})

请求一下试试,返回结果为

我们在第二个中间件中执行一下异步操作,我们改造之后的代码如下

js 复制代码
const koa = require('koa')
const axios = require('axios')

const app = new koa()


app.use((ctx, next) => {
  console.log("第一个全局中间件")
  ctx.msg = "aaa"
  next()

  // 返回的数据
  ctx.body = ctx.msg
  console.log("执行完毕返回第一个中间件")
})

app.use(async (ctx, next) => {
  console.log("第二个中间件")
  const res = await axios.get('http://localhost:8001/')
  ctx.msg += res.data.data
  next()
  console.log("执行完毕返回第二个中间件")
})

app.use((ctx, next) => {
  console.log("第三个中间件")
  ctx.msg += 'ccc'
})

app.listen(8000, () => {
  console.log("服务运行在8000端口")
})

我们启动服务然后请求下8000端口,我们发下并没有按照之前中间件的顺序进行执行,而是直接将异步操作给跳过去直接执行了第三个中间件。

我们得出的结果是,在koa中当中间件执行异步的时候那么next不会默认等到结果而是直接执行下一个中间件,如果希望得到异步执行的结果就需要在next之前添加await,并且中间件的返回顺序也发生了变化。

接下来我们试试看下。

js 复制代码
const koa = require('koa')
const axios = require('axios')

const app = new koa()


app.use(async (ctx, next) => {
  console.log("第一个全局中间件")
  ctx.msg = "aaa"
  await next()

  // 返回的数据
  ctx.body = ctx.msg
  console.log("执行完毕返回第一个中间件")
})

app.use(async (ctx, next) => {
  console.log("第二个中间件")
  const res = await axios.get('http://localhost:8001/') || 'sss'
  ctx.msg += res.data.data
  await next()
  console.log("执行完毕返回第二个中间件")
})

app.use((ctx, next) => {
  console.log("第三个中间件")
  ctx.msg += 'ccc'
})

app.listen(8000, () => {
  console.log("服务运行在8000端口")
})

我们也可以通过控制台来看下执行顺序。

所以当我们在使用koa进行异步操作的时候,如果需要拿到异步的值那就需要在next之前添加await才可以实现我们想要的结果。

三.Express的同步操作和异步操作


😳上面我们学习了koa的同步操作和异步操作,接下来我们尝试着测试一下Express中间件的操作。

js 复制代码
const express = require('express')

const app = express()

// 编写中间件
app.use((req,res,next)=>{
  console.log("中间件一");
  req.msg = "111"
  next()
  res.json(req.msg)
})

// 中间件2
app.use((req,res,next)=>{
  console.log("中间件二");
  req.msg = "222"
  next()
})

// 中间件3

app.use((req,res,next)=>{
  console.log("中间件三");
  req.msg = "333"
})

app.listen(8000,()=>{
  console.log("服务部署在8000端口");
})

koa一样我们对这个服务进行启动,然后通过接口访问的客户端来进行请求,我们可以看到在执行同步的代码的时候执行的顺序和koa框架的执行顺序是一样的,均是依次执行。

既然顺序是依次执行那么时候会在第一个中间件中进行返回哪?我们可以看下结果。

我们可以看到是可以正常返回的,因此我们可以得出一个结论,在执行同步代码的时候Express框架和koa框架没有任何区别。


😎接下来我们看下在异步操作的时候他们之间的区别,我们对我们的代码进行改造在中间件中加入异步请求,我们首先先在本地搭建一个简单的接口。

js 复制代码
const koa = require('koa')
const app = new koa()

app.use((ctx,next)=>{
    ctx.body = {
        name:'aaa',
        age:12
    }

})

app.listen(8001,()=>{
    console.log("服务启动在8001端口");
})

然后将接口跑在8001端口,然后我们写我们的代码,让其请求这个接口。

js 复制代码
const express = require('express')
const axios = require('axios')
const app = express()

// 编写中间件
app.use((req,res,next)=>{
    console.log("中间件一");
    req.msg = "111"
    next()
    res.json('asdfg')
})

// 中间件2
app.use((req,res,next)=>{
    console.log("中间件二");
    req.msg += '222'
    next()
})

// 中间件3

app.use( async(req,res,next)=>{
    console.log("中间件三");
    const resData = await  axios.get('http://127.0.0.1:8001/')
    req.msg += resData.data.name
})

app.listen(8000,()=>{
    console.log("服务部署在8000端口");
})

我们在请求工具中进行请求,请求完成后我们看下请求工具中的数据。

并没有按照我们的预期返回接口返回的内容,在Express中像koa那样处理异步完全是没有效果的,因为Express中遇到异步的时候只能放在最后一个中间件中获取到每个中间件处理的数据,就像下面代码一样。

js 复制代码
const express = require('express')
const axios = require('axios')
const app = express()

// 编写中间件
app.use((req,res,next)=>{
    console.log("中间件一");
    req.msg = "111"
    next()
})

// 中间件2
app.use((req,res,next)=>{
    console.log("中间件二");
    req.msg += '222'
    next()
})

// 中间件3

app.use( async(req,res,next)=>{
    console.log("中间件三");
    const resData = await  axios.get('http://127.0.0.1:8001/')
    req.msg += resData.data.name
    res.json('asdfg')
})

app.listen(8000,()=>{
    console.log("服务部署在8000端口");
})

四.洋葱模型


😎在总结Express和koa的区别的时候我们可以先看一个概念,这个概念的名称叫做,洋葱模型。

也许我们也能够感受到,在我们进行请求的时候请求会通过中间件一层一层的进去,然后会一层一层的返回,并且koa无论是同步还是异步都符合这个模型,而Express框架中由于自身的设计,只有在同步代码的时候才是洋葱模型,当其在中间件中进行异步数据获取的时候,就不符合洋葱模型了。

五.总结


😁Express和koa的核心在于中间件,那么主要差异也在中间件,Express只有在处理同步代码的时候才符合洋葱模型,而koa无论是同步还是异步代码处理的时候都符合洋葱模型,这是两个框架的主要区别,同时也是为什么目前koa的热度越来越高的原因。

相关推荐
千里码aicood37 分钟前
【2025】springboot教学评价管理系统(源码+文档+调试+答疑)
java·spring boot·后端·教学管理系统
程序员-珍1 小时前
使用openapi生成前端请求文件报错 ‘Token “Integer“ does not exist.‘
java·前端·spring boot·后端·restful·个人开发
liuxin334455661 小时前
教育技术革新:SpringBoot在线教育系统开发
数据库·spring boot·后端
架构师吕师傅2 小时前
性能优化实战(三):缓存为王-面向缓存的设计
后端·微服务·架构
bug菌2 小时前
Java GUI编程进阶:多线程与并发处理的实战指南
java·后端·java ee
夜月行者4 小时前
如何使用ssm实现基于SSM的宠物服务平台的设计与实现+vue
java·后端·ssm
Yvemil74 小时前
RabbitMQ 入门到精通指南
开发语言·后端·ruby
sdg_advance4 小时前
Spring Cloud之OpenFeign的具体实践
后端·spring cloud·openfeign
猿java5 小时前
使用 Kafka面临的挑战
java·后端·kafka
碳苯5 小时前
【rCore OS 开源操作系统】Rust 枚举与模式匹配
开发语言·人工智能·后端·rust·操作系统·os