express和koa之间的抉择

Koa 还是 express

关于两者的区别,我这里用一个非常简单的例子演示:

假设我们需要两个功能,第一:实现监控这个请求处理的时长;第二:真正处理请求—这个请求需要从数据库中异步拿一个数据返回给用户。

那么,从合理性考虑,我们一般要使用 2 个中间件来实现这么个需求。 第一个中间件用来关注请求响应时长,第二个中间件关注业务处理-查询数据库拿到数据。而我们为了 resTime 中间件的通用性,又不能采用说:让第一个中间件记录 startTime,然后让第二个中间件处理数据完成后再记录 endTime,再相减的办法。 我们要避免侵入第二个中间件。

如何做呢,我们对比下 Koa 和 express 两者的区别:

  • 在 express 里面,要想实现这个中间件。难点在于如何不侵入地去获得 endTime,这里需要使用一点小技巧,我们知道,express 里面是通过 res.send 手工去发送响应的。因此在我们的通用 resTime 中间件里,可以监听 res 对象的 finish 事件,然后再获取此时的 endTime(参考: https://www.jianshu.com/p/f0ebd8261613)。

    但是,如果希望在响应头里加上 x-response-time 这个 http 头的话,监听 res 的 finish 事件就不太行了,因为这个事件发生时,http 头已经响应到客户端了。此时要想实现这个功能,需要深度覆盖 res 的 writeHead 方法,参考:https://zhuanlan.zhihu.com/p/32049820

    问个问题: express 能进行中间件的控制流转吗?
    答:其实是可以的。express 里面 next 就是把控制流转到下一个中间件,下一个中间件执行完毕后就会回到你调用 next 的地方的下一句代码来执行。 准确的说,这里就是函数的正常跳转执行啦。因此这里必然会出现异步无法感知的问题,即中间件 A 里面 next 调用中间件 B,中间件 B 里的同步代码执行完毕后会立马回到中间件 A 的 next 位置继续向下执行,而无法做到等待中间件 B 的异步完成再回到 A 中 next 的位置。(相当于中间件 B 没办法暂停,就导致中间件 2 很快就当做执行完毕了)

  • Koa。 Koa 得益于 generator 或 async 对用同步代码来书写对异步的等待。从而可以实现:控制权流转到第二个中间件后,中间件 2 中也可以通过 await 或 yield 来等待异步任务的完成,而不是立马执行完毕。因此可以实现”中间件 B 的异步任务完成之后才算执行完整个中间件 B,然后再回到中间件 A”,从而很容易地就能实现 x-response-time 这个需求了。

同时,在 Koa 里面所有中间件的功能,改成了去创建响应头和响应体的内容,而不是手工去向客户端发送内容。这样也更加允许中间件灵活的流转控制。