Node.js 是一個異步的世界,官方 API 支持的都是 callback 形式的異步編程模型,這會帶來許多問題,例如
因此社區(qū)提供了各種異步的解決方案,最終勝出的是 Promise,它也內置到了 ECMAScript 2015 中。而在 Promise 的基礎上,結合 Generator 提供的切換上下文能力,出現(xiàn)了 co 等第三方類庫來讓我們用同步寫法編寫異步代碼。同時,async function 這個官方解決方案也于 ECMAScript 2017 中發(fā)布,并在 Node.js 8 中實現(xiàn)。
async function 是語言層面提供的語法糖,在 async function 中,我們可以通過 await 關鍵字來等待一個 Promise 被 resolve(或者 reject,此時會拋出異常), Node.js 現(xiàn)在的 LTS 版本(8.x)已原生支持。
const fn = async function() { |
Koa 是一個新的 web 框架,由 Express 幕后的原班人馬打造, 致力于成為 web 應用和 API 開發(fā)領域中的一個更小、更富有表現(xiàn)力、更健壯的基石。
Koa 和 Express 的設計風格非常類似,底層也都是共用的同一套 HTTP 基礎庫,但是有幾個顯著的區(qū)別,除了上面提到的默認異步解決方案之外,主要的特點還有下面幾個。
Koa 的中間件和 Express 不同,Koa 選擇了洋蔥圈模型。
所有的請求經(jīng)過一個中間件的時候都會執(zhí)行兩次,對比 Express 形式的中間件,Koa 的模型可以非常方便的實現(xiàn)后置處理邏輯,對比 Koa 和 Express 的 Compress 中間件就可以明顯的感受到 Koa 中間件模型的優(yōu)勢。
和 Express 只有 Request 和 Response 兩個對象不同,Koa 增加了一個 Context 的對象,作為這次請求的上下文對象(在 Koa 1 中為中間件的 this,在 Koa 2 中作為中間件的第一個參數(shù)傳入)。我們可以將一次請求相關的上下文都掛載到這個對象上。類似 traceId 這種需要貫穿整個請求(在后續(xù)任何一個地方進行其他調用都需要用到)的屬性就可以掛載上去。相較于 request 和 response 而言更加符合語義。
同時 Context 上也掛載了 Request 和 Response 兩個對象。和 Express 類似,這兩個對象都提供了大量的便捷方法輔助開發(fā),例如
通過同步方式編寫異步代碼帶來的另外一個非常大的好處就是異常處理非常自然,使用 try catch 就可以將按照規(guī)范編寫的代碼中的所有錯誤都捕獲到。這樣我們可以很便捷的編寫一個自定義的錯誤處理中間件。
async function onerror(ctx, next) { |
只需要將這個中間件放在其他中間件之前,就可以捕獲它們所有的同步或者異步代碼中拋出的異常了。
如上述,Koa 是一個非常優(yōu)秀的框架,然而對于企業(yè)級應用來說,它還比較基礎。
而 Egg 選擇了 Koa 作為其基礎框架,在它的模型基礎上,進一步對它進行了一些增強。
在基于 Egg 的框架或者應用中,我們可以通過定義 app/extend/{application,context,request,response}.js 來擴展 Koa 中對應的四個對象的原型,通過這個功能,我們可以快速的增加更多的輔助方法,例如我們在 app/extend/context.js 中寫入下列代碼:
// app/extend/context.js |
在 Controller 中,我們就可以使用到剛才定義的這個便捷屬性了:
// app/controller/home.js |
更多關于擴展的內容,請查看擴展章節(jié)。
眾所周知,在 Express 和 Koa 中,經(jīng)常會引入許許多多的中間件來提供各種各樣的功能,例如引入 koa-session 提供 Session 的支持,引入 koa-bodyparser 來解析請求 body。而 Egg 提供了一個更加強大的插件機制,讓這些獨立領域的功能模塊可以更加容易編寫。
一個插件可以包含
一個獨立領域下的插件實現(xiàn),可以在代碼維護性非常高的情況下實現(xiàn)非常完善的功能,而插件也支持配置各個環(huán)境下的默認(最佳)配置,讓我們使用插件的時候幾乎可以不需要修改配置項。
egg-security 插件就是一個典型的例子。
更多關于插件的內容,請查看插件章節(jié)。
Egg 1.x 發(fā)布時,Node.js 的 LTS 版本尚不支持 async function,所以 Egg 1.x 仍然基于 Koa 1.x 開發(fā),但是在此基礎上,Egg 全面增加了 async function 的支持,再加上 Egg 對 Koa 2.x 的中間件也完全兼容,應用層代碼可以完全基于 async function 來開發(fā)。
Node.js 8 正式進入 LTS 后,async function 可以在 Node.js 中使用并且沒有任何性能問題了,Egg 2.x 基于 Koa 2.x,框架底層以及所有內置插件都使用 async function 編寫,并保持了對 Egg 1.x 以及 generator function 的完全兼容,應用層只需要升級到 Node.js 8 即可從 Egg 1.x 遷移到 Egg 2.x。
更多建議: