Egg.js 与 Koa


    • callback hell: 最臭名昭著的 callback 嵌套问题。
    • : 异步函数中可能同步调用 callback 返回数据,带来不一致性。

    因此社区提供了各种异步的解决方案,最终胜出的是 Promise,它也内置到了 ECMAScript 2015 中。而在 Promise 的基础上,结合 Generator 提供的切换上下文能力,出现了 co 等第三方类库来让我们用同步写法编写异步代码。同时, 这个官方解决方案也于 ECMAScript 2017 中发布,并在 Node.js 8 中实现。

    async function 是语言层面提供的语法糖,在 async function 中,我们可以通过 关键字来等待一个 Promise 被 resolve(或者 reject,此时会抛出异常), Node.js 现在的 LTS 版本(8.x)已原生支持。

    Koa 和 Express 的设计风格非常类似,底层也都是共用的,但是有几个显著的区别,除了上面提到的默认异步解决方案之外,主要的特点还有下面几个。

    Middleware

    Koa 的中间件和 Express 不同,Koa 选择了洋葱圈模型。

    • 中间件洋葱图:

    • 中间件执行顺序图:

    Egg.js 和 Koa - 图2

    和 Express 只有 Request 和 Response 两个对象不同,Koa 增加了一个 Context 的对象,作为这次请求的上下文对象(在 Koa 1 中为中间件的 this,在 Koa 2 中作为中间件的第一个参数传入)。我们可以将一次请求相关的上下文都挂载到这个对象上。类似 这种需要贯穿整个请求(在后续任何一个地方进行其他调用都需要用到)的属性就可以挂载上去。相较于 request 和 response 而言更加符合语义。

    同时 Context 上也挂载了 Request 和 Response 两个对象。和 Express 类似,这两个对象都提供了大量的便捷方法辅助开发,例如

    • get request.query
    • set response.body

    异常处理

    通过同步方式编写异步代码带来的另外一个非常大的好处就是异常处理非常自然,使用 就可以将按照规范编写的代码中的所有错误都捕获到。这样我们可以很便捷的编写一个自定义的错误处理中间件。

    只需要将这个中间件放在其他中间件之前,就可以捕获它们所有的同步或者异步代码中抛出的异常了。

    如上述,Koa 是一个非常优秀的框架,然而对于企业级应用来说,它还比较基础。

    而 Egg 选择了 Koa 作为其基础框架,在它的模型基础上,进一步对它进行了一些增强。

    在基于 Egg 的框架或者应用中,我们可以通过定义 app/extend/{application,context,request,response}.js 来扩展 Koa 中对应的四个对象的原型,通过这个功能,我们可以快速的增加更多的辅助方法,例如我们在 app/extend/context.js 中写入下列代码:

    更多关于扩展的内容,请查看章节。

    插件

    众所周知,在 Express 和 Koa 中,经常会引入许许多多的中间件来提供各种各样的功能,例如引入 提供 Session 的支持,引入 koa-bodyparser 来解析请求 body。而 Egg 提供了一个更加强大的插件机制,让这些独立领域的功能模块可以更加容易编写。

    一个插件可以包含

    • extend:扩展基础对象的上下文,提供各种工具类、属性。
    • middleware:增加一个或多个中间件,提供请求的前置、后置处理逻辑。
    • config:配置各个环境下插件自身的默认配置项。

    一个独立领域下的插件实现,可以在代码维护性非常高的情况下实现非常完善的功能,而插件也支持配置各个环境下的默认(最佳)配置,让我们使用插件的时候几乎可以不需要修改配置项。

    插件就是一个典型的例子。

    更多关于插件的内容,请查看插件章节。

    Egg 1.x

    Egg 1.x 发布时,Node.js 的 LTS 版本尚不支持 async function,所以 Egg 1.x 仍然基于 Koa 1.x 开发,但是在此基础上,Egg 全面增加了 async function 的支持,再加上 Egg 对 Koa 2.x 的中间件也完全兼容,应用层代码可以完全基于 来开发。

    • 底层基于 Koa 1.x,异步解决方案基于 co 封装的 generator function。
    • 官方插件以及 Egg 核心使用 generator function 编写,保持对 Node.js LTS 版本的支持,在必要处通过 co 包装以兼容在 async function 中的使用。
    • 应用开发者可以选择 async function(Node.js 8.x+) 或者 generator function(Node.js 6.x+)进行编写。

    Egg 2.x

    • 底层基于 Koa 2.x,异步解决方案基于 async function。
    • 官方插件以及 Egg 核心使用 async function 编写。
    • 建议业务层迁移到 async function 方案。
    • 只支持 Node.js 8 及以上的版本。