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的錯,並且提示語也不多。第一次遇到的時候用了好久才找到原因所在,希望其他小伙伴引以為戒,既然使用某個框架一定要遵循其要求。