做者: gauseen
原文: https://github.com/gauseen/blog
Koa.js
是一個極其精簡的 Web 服務框架,主要提供如下功能:前端
HTTP
服務:主要處理 request
和 response
AOP
爲 Aspect Oriented Programming 的縮寫,中文意思爲:面向切面編程,它是函數式編程的一種衍生範式git
舉個栗子 :github
假如我想把一個蘋果(源數據)處理成果盤(最終數據)我該怎麼作?編程
① 蘋果(源數據) ---->
② 洗蘋果 ---->
③ 切蘋果 ---->
④ 放入盤子 ---->
⑤ 果盤(最終數據)設計模式
共有 5 個步驟,若是我想升級一下果盤,打算在切蘋果以前先削皮,放入盤子後擺成五角星形狀那麼個人步驟應該以下:瀏覽器
① 蘋果(源數據) ---->
② 洗蘋果 ---->
③ 削皮 ---->
④ 切蘋果 ---->
⑤ 放入盤子 ---->
⑥ 擺成五角星形狀 ---->
⑦ 果盤(最終數據)app
上面每一個步驟均可以當作相應的方法,步驟 ③ 和 ⑥ 加入與否都不影響我製做出果盤這個結果,能夠看出這樣是很是靈活的框架
其實這就是生活中面向切面編程的例子,
換句話說,就是在現有程序中,加入或減去一些功能不影響原有的代碼功能。koa
Koa.js
洋蔥模型?洋蔥模型其實就是中間件處理的流程,中間件生命週期大體有:async
多箇中間件處理,就造成了所謂的洋蔥模型,它是 AOP
面向切面編程的一種應用。
結合一下上面的果盤例子可知,在 Koa.js 中,蘋果(源數據)就是 請求數據 request
,果盤(最終數據)就是 響應數據 response
,中間處理的過程就是 Koa2.js 的中間件函數處理的過程
一張經典的洋蔥切面圖以下:
先回顧一下,Koa2.js 中下面代碼打印輸出順序爲:
const Koa = require('koa') const app = new Koa() app.use(async (cxt, next) => { console.log('middleware_01 start') await next() console.log('middleware_01 end') }) app.use(async (cxt, next) => { console.log('middleware_02 start') await next() console.log('middleware_02 end') }) app.use(async (cxt, next) => { console.log('middleware_03 start') console.log('middleware_03 end') }) app.listen(3000)
// 瀏覽器訪問:http://localhost:3000 // 輸出順序爲: middleware_01 start middleware_02 start middleware_03 start middleware_03 end middleware_02 end middleware_01 end
想想,怎樣才能實現 Koa.js 中間件處理機制呢?
// 函數處理的數據 let context = {} function middleware_01 (cxt) { console.log('middleware_01 start') middleware_02(cxt) console.log('middleware_01 end') } function middleware_02 (cxt) { console.log('middleware_02 start') middleware_03(cxt) console.log('middleware_02 end') } function middleware_03 (cxt) { console.log('middleware_03 start') console.log('middleware_03 end') } // 調用中間件 compose 函數 function compose () { // 默認調用第一個中間件 middleware_01(context) } compose() // 輸出結果以下,與上面中間件一致: middleware_01 start middleware_02 start middleware_03 start middleware_03 end middleware_02 end middleware_01 end
上面代碼雖然實現了,可是有不足點,如:
const App = function () { // 中間件公共的處理數據 let context = {} // 中間件隊列 let middlewares = [] return { // 將中間件放入隊列中 use (fn) { middlewares.push(fn) }, // 調用中間件 callback () { // 初始調用 middlewares 隊列中的第 1 箇中間件 return dispatch(0) function dispatch (i) { // 獲取要執行的中間件函數 let fn = middlewares[i] // 執行中間件函數,回調參數是:公共數據、調用下一個中間件函數 // 返回一個 Promise 實例 return Promise.resolve( fn(context, function next () { dispatch(i + 1) }) ) } }, } }
上面代碼,在不考慮特殊邊界狀況下,就完成了 Koa2.js 中簡易版中間件的封裝,讓咱們來測試一下
// 測試代碼 let app = App() app.use(async (cxt, next) => { console.log('middleware_01 start') await next() console.log('middleware_01 end') }) app.use(async (cxt, next) => { console.log('middleware_02 start') await next() console.log('middleware_02 end') }) app.use(async (cxt, next) => { console.log('middleware_03 start') console.log('middleware_03 end') }) // Koa2.js 源碼中,放在 http.createServer(callback) 回調中調用 // 這裏咱們直接調用 app.callback() // 輸出以下: middleware_01 start middleware_02 start middleware_03 start middleware_03 end middleware_02 end middleware_01 end
想更深刻的瞭解 Koa2.js 洋蔥模型可在這裏看源碼
歡迎關注無廣告文章公衆號:學前端
<!-- 引用 -->