摘要:任何一層報錯,都能用捕獲總結是一個非常輕量級的框架,只實現了中間件處理流程和對對象的封裝。其他的功能都由外部中間件提供。
koa 的中間件機制巧妙的運用了閉包和 async await 的特點,形成了一個洋蔥式的流程,和 JS 的事件流 (捕獲 -> target -> 冒泡) 相似
handleRequest(ctx, fnMiddleware) { const res = ctx.res; res.statusCode = 404; const onerror = err => ctx.onerror(err); const handleResponse = () => respond(ctx); onFinished(res, onerror); return fnMiddleware(ctx).then(handleResponse).catch(onerror); }
上述代碼是 request 事件的句柄,也就是說每一個請求到來,都會執行這個總方法
onerror 為請求設置了錯誤處理的方法
handleResponse 是當中間件完成后給瀏覽器返回 response 的方法,里面是原生的 res.end(body)
onFinished 是判斷請求最終有沒有完成,根據不同的結果采取不同的策略
fnMiddleware(ctx) 就是執行所有中間件函數,然后返回一個 Promise 對象,不出錯的話執行 handleResponse
洋蔥式的中間件值得一提的是,中間件原理的代碼并沒有放在 koa 中,而是多帶帶打了一個模塊,叫做 ==koa-compose==
function (context, next) { // last called middleware # let index = -1 return dispatch(0) function dispatch (i) { if (i <= index) return Promise.reject(new Error("next() called multiple times")) index = i let fn = middleware[i] if (i === middleware.length) fn = next // 返回給 next() if (!fn) return Promise.resolve() try { // 返回給 next(),最外一層返回給 fnMiddleware(ctx).then(handleResponse) return Promise.resolve(fn(context, function next () { // 返回給外一層 fn 的 await return dispatch(i + 1) })) } catch (err) { return Promise.reject(err) } } }
執行一次 dispatch 就是執行一個中間件,算是洋蔥的一層
每個 dispatch 都會返回一個 Promise.resolve 給外面一層的 await(除了第一次,他返回給的是 fnMiddleware(ctx).then(handleResponse))
每個 dispatch 都有一個自己的序號,也就是參數 i (他用閉包控制住了) ,從 0 開始
閉包里有一個 index,是記錄執行過的中間件數量。一旦有序號大于數量,說明有中間件執行了兩次 await next,這是不被允許的
每一層用 Promise.resolve 包裹是因為 await 需要接收一個 Promise 對象
下面就是中間件原理的展開寫法,仔細琢磨吧
function dispatch(0){ // 第一層的序號 return Promise.resolve(async function a0(){ cnosole.log("0-0") await 111(function next0(){ return (function dispatch(1){ // 第二層的序號 return Promise.resolve(async function a1(){ cnosole.log("1-0") await 222(function next1(){ return (function dispatch(2){ // 第三層的序號 return Promise.resolve(async function a2(){ cnosole.log("2-0") await 333(function next2(){ return (function dispatch(3){ // i == middleware.length ,算是洋蔥芯吧 // fn[3] == undefined,說明中間件已經到洋蔥的最里面了,開始向外返回 return Promise.resolve() })() })()333 console.log("2-1") }) })() })()222 console.log("1-1") }) })() })()111 console.log("0-1") }) } dispatch(0).then(handleResponse)思考 1. 普通函數采用 dispatch 算法也能取得洋蔥式的流程,為何要使用 async ?
app.use(async function (ctx,next) { console.log("1-1") await new Promise(function(resolve, reject){ setTimeout(function () { console.info ("wait for 10 mini seconds."); resolve(); },10); }); console.log("1-2") next(); console.log("1-3") }) app.use(async function (ctx,next) { console.log("2-1") await new Promise(function(resolve){ setTimeout(function () { console.info ("wait for 10 mini seconds"); resolve(); },10); }); console.log("2-2") next(); console.log("2-3") })
試試 next() 前面加上 await 和不加 await 的區別就明白了2. 為何要用 Promise.resolve 返回
因為他是洋蔥式的層級,如果用普通的 Boolean 返回的話,只能返回到上一層,沒法全局獲取,對錯誤的把控難以控制。Promise 任何一層報錯,都能用 catch 捕獲總結
koa 是一個非常輕量級的框架,只實現了中間件處理流程和對 res、req 對象的封裝。其他的功能都由外部中間件提供。代碼不是很多,但是很精妙,對于代碼能力的提高有不小的幫助END
?
?
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/94307.html
摘要:啟動流程主要的啟動流程就是下面的步引入包實例化編寫中間件監聽服務器引入包引入包其實就是引入的一個繼承于原生的類的類其中就包含了等原型方法實例化執行,將等對象封裝在實例中編寫中間件首先判斷的類型,不是方法直接拋錯是生成器函數的話用封裝是函數 啟動流程 koa 主要的啟動流程就是下面的 4 步:引入 koa 包 => 實例化 koa => 編寫中間件 => 監聽服務器 const koa ...
摘要:實現的四大模塊上文簡述了源碼的大體框架結構,接下來我們來實現一個的框架,筆者認為理解和實現一個框架需要實現四個大模塊,分別是封裝創建類構造函數構造對象中間件機制和剝洋蔥模型的實現錯誤捕獲和錯誤處理下面我們就逐一分析和實現。 什么是koa框架? ? ? ? ?koa是一個基于node實現的一個新的web框架,它是由express框架的原班人馬打造的。它的特點是優雅、簡潔、表達力強、自由度...
摘要:實現的四大模塊上文簡述了源碼的大體框架結構,接下來我們來實現一個的框架,筆者認為理解和實現一個框架需要實現四個大模塊,分別是封裝創建類構造函數構造對象中間件機制和剝洋蔥模型的實現錯誤捕獲和錯誤處理下面我們就逐一分析和實現。 什么是koa框架? ? ? ? ?koa是一個基于node實現的一個新的web框架,它是由express框架的原班人馬打造的。它的特點是優雅、簡潔、表達力強、自由度...
閱讀 2772·2021-11-02 14:42
閱讀 3163·2021-10-08 10:04
閱讀 1184·2019-08-30 15:55
閱讀 1025·2019-08-30 15:54
閱讀 2311·2019-08-30 15:43
閱讀 1680·2019-08-29 15:18
閱讀 863·2019-08-29 11:11
閱讀 2362·2019-08-26 13:52