Express 和 Koa 的比较
节选自 loopback4-improves-inbound-http-processing
Traditionally in Express (and Connect), functions implementing request handling logic have the following signature:
function (req, res, next);
While it’s amazing how powerful this simple signature is, it comes with major flaws too:
-
Because the list of arguments is given, it’s difficult to pass additional data between different handlers. The convention is to attach custom properties to the Request object, e.g. body-parsing middleware sets
req.body
property. This approach is difficult to describe in TypeScript and the ever-changing shape of the Request object has negative impact on (micro)performance. -
Flow control is difficult to map to Promises and async/await. Execution of a middleware handler has three possible outcomes:
i. The request was handled and the remaining items in the middleware chain are skipped. Implementation wise, middleware did not call
next()
.ii. The middleware modified the request/response objects, or a route did not match the requested path, and the next handler in the middleware chain should be executed. Implementation wise, middleware called
next()
with no arguments.iii. There was an error and request handling should be aborted. Implementation wise, middleware called
next()
with a single argument - the error.
It is difficult to run a piece of code after the request was handled or transform the response before it’s being sent. For example, to print a log line containing information about the request including timing information, one has to register the logging middleware early in the middleware chain so that it can register event observers and/or monkey-patch request/response objects before any actual work is done - this is counter-intuitive since the log line is printed at the end of request handling.
Koa addresses these flaws by introducing an extensible Context object that contains not only the request and response, but also additional properties and helper methods.