express与koa的比较

Express和koa都是服务端的开发框架,服务端开发的重点是对HTTP Request和HTTP Response两个对象的封装和处理,应用的生命周期维护以及视图的处理等。

Express主要基于Connect中间件框架,功能丰富,随取随用,并且框架自身封装了大量便利的功能,比如路由、视图处理等等。而koa主要基于co中间件框架,框架自身并没集成太多功能,大部分功能需要用户自行require中间件去解决,但是由于其基于ES6 generator特性的中间件机制,解决了长期诟病的“callback hell”和麻烦的错误处理的问题,大受开发者欢迎。

connect的执行流程
通常我们都说connect的中间件模型是线性的, 也就是一个一个往下执行的, 如下图:


req/res
req/res
响应
响应
m 1
m 2
m 3
client
client

这么说当然是没错的, 但是当我们执行下面代码的时候可能会有那么一点小小的困惑:

const connect = require('connect')
const app = connect()
app.use(function m1 (req, res, next) {
 console.log('m1')
 next()
 console.log('m1 end')
})
app.use(function m2 (req, res, next) {
 console.log('m2')
 next()
 console.log('m2 end')
})
app.use(function m3 (req, res, next) {
 console.log('m3')
 res.end('hello')
})
app.listen(8080)

当我们访问http://127.0.0.1:8080的时候, 控制台会打印如下:

m1
m2
m3
m2 end
m1 end

这么个结果跟我们上面的模型似乎有点出入, 不是说线性的吗, 为什么next后面的代码还会继续执行? 当然这个我们再之前已经有过结论了, 有兴趣的可以详细瞧瞧, 我们现在直接拿来结果, connect的中间件模型伪代码表示如下:

http.createServer(function (req, res) {
 m1 (req, res) {
 m2 (req, res) {
 m3 (req, res) {}
 }
 }
})

可以看到就是一层一层嵌套的回调, 那么再把我们之前有点疑问的代码简化一下:

http.createServer(function (req, res) {
 console.log('m1')
 m1 (req, res) {
 console.log('m2')
 m2 (req, res) {
 m3 (req, res) {
 console.log('m3')
 res.end('hello')
 }
 }
 console.log('m2 end')
 }
 console.log('m1 end')
})

千万别被上面的回调绕晕了, 就是很简单的回调函数, 一切都解释的通了: 即使res.end之后, 我们的代码还是要继续往下走的, 可以这么说connect的中间件其实也是洋葱形的, 但是因为作为同步代码, 一般不会这么做罢了, 那么上面我们可以重新描述一下connect的中间件模型了:


Koa的执行流程

同样我们再Koa源码分析, 也是说过Koa的中间件模型: 洋葱形

在这里插入图片描述

以下面代码为例:

const Koa = require('koa')
const app = new Koa()
app.use(async function m1 (ctx, next) {
 console.log('m1')
 await next()
 console.log('m1 end')
})
app.use(async function m2 (ctx, next) {
 console.log('m2')
 await next()
 console.log('m2 end')
})
app.use(async function m3 (ctx) {
 console.log('m3')
 ctx.body = 'hello'
})
app.listen(8080)

访问服务, 输出:

m1
m2
m3
m2 end
m1 end

emm 貌似跟connect没差别, 之前看过一篇文章, 实验到这里得到了一个koa和express的中间件模型没差别的结论, 包括我也是很迷惑, 当然是有差别的, 结论后面讲. 同样这里直接拿出koa中间件的简化模型:

Promise.resolve(async m1 () {
 console.log(m1)
 await Promise.resolve(async m2 () {
 console.log(m2)
 await Promise.resolve(async m3 () {
 console.log(m3)
 ctx.body = 'xxx'
 })
 console.log(m2 end)
 })
 console.log(m1 end)
})

我们知道async/await的作用是’同步化’异步操作(看上去如此, 其实不是, 但是我们不需要去管), 那这里的Promise理所当然的被’同步’了, 也就是说console.log(m3 end)的一切异步操作都可以’同步化’.

结论

说出结论之前我们其实可以想一下, 既然connect的中间件也是洋葱形的, 那么跟koa一样的用法似乎也没啥毛病, 那么我来设想一下, 我们的服务需要取数据库里的的一个用户假设是getUser吧, getUser当然是异步的. 分别来看看connect和koa的做法吧:

// connect
app.use(function (req, res) {
 getUser(user => res.end(user))
})
// Koa
app.use(async (ctx) => {
 const user = await getUser()
 ctx.body = user
})

当然这么看似乎没啥差别. 那直接给出结论吧(憋): connect的中间件是同步, 不会’等’其他异步操作, koa则可以’等’异步操作. 当然你不等也没啥问题。

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值