再谈express与koa的对比

之前其实写过一篇express和koa的对比, 可是后来发现里面有很多谬误. 因此一直惦记着纠正一下以前的错误, 尤为关于中间件部分的对比.数据库

这里的express就拿更加简单的connect代替express

connect的执行流程

一般咱们都说connect的中间件模型是线性的, 也就是一个一个往下执行的, 以下图:app

image

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

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的中间件模型伪代码表示以下:async

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的中间件模型了:源码分析

image

Koa的执行流程

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

如下面代码为例:ui

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则能够'等'异步操做. 固然你不等也没啥问题.

有啥问题能够互相交流哈.

image

相关文章
相关标签/搜索