koa+orm2
koa是由 Express 原班人馬打造的新的web框架。套用其官方的說法:Koa 應用是一個包含一系列中間件 generator 函數的對象。 這些中間件函數基於 request 請求以一個類似於棧的結構組成並依次執行。
koa的中間件系統原理:
Koa的精妙之處就在於其基於promise的中間件系統的實現,避免了免除重復繁瑣的回調函數嵌套。Koa的中間件是一系列generator函數的對象,執行起來有點類似於棧的結構,依次執行。從網上找到一張圖可以比較形象的說明koa的中間件是如何工作的:

每個中間件都是generator函數,當一個請求過來的時候,會依次經過各個中間件進行處理,當遇到await next()時,Koa 暫停了該中間件,執行下一個中間件。直到某個中間件不調用下個中間件,即沒有處理await next()。則kao會逆序向上依次執行被暫停的中間件的剩余部分邏輯。
代碼實例如下:
1 const Koa = require('koa');
2 const app = new Koa();
3 /**
4 * 請求依次進入下面三個中間件
5 * */
6 // x-response-time
7 app.use(async function (ctx, next) {
8 /**
9 * 首先獲得start時間
10 * */
11 const start = new Date();
12 /**
13 * 遇到next中間件的調用,則暫停該中間件。執行下一個即logger
14 * */
15 await next();
16 /**
17 * logger,完全執行之后,繼續下面的部分
18 * */
19 const ms = new Date() - start;
20 console.log('X-Response-Time', `${ms}ms`);
21 /**
22 * 至此,整個請求執行結束。
23 * */
24
25 });
26 // logger
27 app.use(async function (ctx, next) {
28 const start = new Date();
29 /**
30 * 獲得start之后,暫停。執行response
31 * */
32 await next();
33 /**
34 * response執行之后,獲得執行權繼續執行下面邏輯。
35 * */
36 const ms = new Date() - start;
37 console.log(`${ctx.method} ${ctx.url} - ${ms}`);
38 /**
39 * 執行完畢,將執行權交個上個中間件,即x-response-time
40 * */
41 };
42 //response
43 app.use(async function(ctx,next){
44 /**
45 * 執行之后,沒有下一個中間件的調用,即 await next();
46 * 則向上執行logger,余下的部分
47 * */
48 ctx.body = 'Hello World';
49 })
50
51 app.listen(3000);
上面代碼執行的順序為:
1、請求開始時,請求先經過 x-response-time, 當遇到await next()時,暫停當前調用下個中間件。
2、logger 中間件執行當遇到await next()時,暫停當前調用下個中間件。
3、reponse 中間件執行,執行完成,將控制權交給上個中間件即logger。
4、logger執行await next()后面的邏輯,打印相應信息。完成之后,將控制權交給上個中間件即 x-response-time。
5、 x-response-time執行剩下的部分,打印相應信息。
當我們使用koa的時候,應該通過use添加一個中間件,處理相關的任務。注意該中間件也應該按照koa的要求為generator函數的形式。
kao+node-orm2需要注意的部分:
作為Node.js 的ORM框架orm2也是比較流行的。作為后端開發的時候,與express框架的結合也是比較合適的。如果想要配合koa的使用就要注意一下。
前面提到的koa的中間件是要求generator函數,起碼基於promise。而orm2數據庫連接則是原本的回調方式進行的。
var orm = require('orm');
orm.connect('mysql://root:password@localhost/test', function(err, db) {
if (err) return console.error('Connection error: ' + err);
// connected
// ...
});
這樣兩者就不能很好的合並使用了。如果想要同時使用的話,解決方法也是比較鮮明的,如何讓orm2處理數據庫連接等api以promise的方式暴露出來。
解決方式還是比較多的,比較方便的是,使用對orm2進行了promise包裝的qOrm來代替直接引用orm。然后通過app.use引入即可。這樣的話數據庫連接中間件的代碼可以如下:
1 var orm = require('orm');
2 var qOrm = require('q-orm');
3 var dbSet = require('../../config/setting');
4
5 var connection = null;
6
7 function setup(db) {
8 require('../models/demoModel')(qOrm, db);
9 require('../models/personModel')(qOrm, db);
10 require('../models/questionModel')(qOrm, db);
11 }
12 module.exports = async function (ctx,next) {
13 if (connection){
14 await next();
15 } else{
16 await qOrm.qConnect(dbSet).then(function(db){
17 connection = db;
18 setup(db);
19 ctx.req.models = db.models;
20 ctx.req.db = db;
21 });
22 await next();
23 }
24 };
使用koa一定要理解koa的基本思想,即通過中間件系統依次處理不同任務。這就要求各部分必須滿足koa中間件的要求:中間件為ggenerator,而傳統的回調方式進行處理的方法不會返回promise的對象給koa來判斷當前處理次序。因此會報Module not found的錯,並且提示語也不多。第一次遇到的時候用了好久才找到原因所在,希望其他小伙伴引以為戒,既然使用某個框架一定要遵循其要求。

