示例代碼託管在:http://www.github.com/dashnowords/blogshtml
博客園地址:《大史住在大前端》原創博文目錄前端
華爲雲社區地址:【你要的前端打怪升級指南】node
在中間件系統的實現上,KOA
中間件經過async/await
來在不一樣中間件之間交換控制權,工做機制和棧結構很是類似,建議結合《express中間件系統的基本實現》對比學習,兩個框架所基於的語法特性有區別(express
使用ES5
的回調風格語法,KOA
使用ES7
的扁平式異步async/await
風格語法),但在框架基本原理上是很相似的,只是中間件寫法和遍歷機制稍有不一樣。git
初始化方法github
let middleware = new MiddleWare();
添加中間件函數的方法web
//Fn爲被添加的中間件,KOA中間件爲async函數 middleware.use(Fn);
預處理中間件棧express
//將存儲於數組中的各個中間件組合爲按照「先進後出」原則執行的中間件系統。 middleware.start = middleware.compose();
啓動中間件隊列api
middleware.start(ctx);
/* * KOA中間件框架的基本實現 */ class MiddleWare { constructor(){ this.queue = [] } //添加中間件函數 use(fn){ this.queue.push(fn); } //合併中間件處理流,是一個高階函數,調用一次後會生成真正須要的函數。 compose(){ return function (ctx, next) { let _this= this; let index = -1; return dispatch(0); /** * KOA中間件的工做的步進函數 */ function dispatch(i) { index = i; //依次取用數組中添加的中間件函數 let fn = i === _this.queue.length ? next : _this.queue[i]; if(!fn){ return Promise.resolve(); } try{ /* *中間件函數的形式爲 async fn(ctx, next),能夠看到此處透傳了ctx的引用, *同時next是一個延遲執行中間件隊列中下一個中間件的函數,也就是說若是在前 *一箇中間件的函數體中調用 await next(),就會啓動下一個中間件,實際執行 *的函數是dispatch(i+1)。 */ return Promise.resolve(fn(ctx,()=>{ return dispatch(i+1); })); }catch(err){ return Promise.reject(err); } } } } }
//添加回調函數 middleware.use(async function(ctx, next){ console.log('step 001'); ctx.info = 'go through middleware1'; await next(); console.log('step 006'); }); middleware.use(async function(ctx, next){ console.log('step 002'); await next(); console.log('step 005'); }); middleware.use(async function(ctx, next){ console.log('step 003'); await next(); console.log('step 004'); });
//初始化 let middleware = new MiddleWare(); /* ...此處爲添加中間件的代碼 */ middleware.start = middleware.compose();
能夠看到有錯誤發生和正常響應時的不一樣結果:數組
用node
起一個web服務器那真是太隨意了~服務器
//啓動http服務 http.createServer(function(req, res){ console.log(req.url); let info = {}; middleware.start(info); res.end(JSON.stringify(info)); }).listen(9527);
看一下效果(訪問服務器時自定義消息就能夠傳至前臺了):