前言
😳大家好,我是一溪风月
程序员界的搬砖工,在Node
专栏中我们已经学习过了Express
与koa
的基本使用 Express
使用的是非常广泛的,包括Nest
默认也是依赖Express
框架,koa相对于Express
比较新,同时从设计层面设计的比较小巧,那么这篇文章我们就来看下Express
和koa
框架的区别以及在同步异步时候的差异。
一.架构设计的差异
- Express是完整和强大的,其中帮助了我们内置了非常多的好用的功能。
- koa是简洁和自由的它只包含最核心的功能,并不会对我们使用其他中间件进行约束。
- 因为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
的热度越来越高的原因。