摘要:前言被認(rèn)為是第二代,它最大的特點就是獨特的中間件流程控制,是一個典型的洋蔥模型。這段代碼就很巧妙的實現(xiàn)了兩點將一路傳下去給中間件將中的下一個中間件作為未來的返回值這兩點也是洋蔥模型實現(xiàn)的核心。
前言
koa被認(rèn)為是第二代node web framework,它最大的特點就是獨特的中間件流程控制,是一個典型的洋蔥模型。koa和koa2中間件的思路是一樣的,但是實現(xiàn)方式有所區(qū)別,koa2在node7.6之后更是可以直接用async/await來替代generator使用中間件,本文以最后一種情況舉例。
洋蔥模型下面兩張圖是網(wǎng)上找的,很清晰的表明了一個請求是如何經(jīng)過中間件最后生成響應(yīng)的,這種模式中開發(fā)和使用中間件都是非常方便的
來看一個koa2的demo:
const Koa = require("koa"); const app = new Koa(); const PORT = 3000; // #1 app.use(async (ctx, next)=>{ console.log(1) await next(); console.log(1) }); // #2 app.use(async (ctx, next) => { console.log(2) await next(); console.log(2) }) app.use(async (ctx, next) => { console.log(3) }) app.listen(PORT); console.log(`http://localhost:${PORT}`);
訪問http://localhost:3000,控制臺打印:
1 2 3 2 1
怎么樣,是不是有一點點感覺了。當(dāng)程序運行到await next()的時候就會暫停當(dāng)前程序,進(jìn)入下一個中間件,處理完之后才會仔回過頭來繼續(xù)處理。也就是說,當(dāng)一個請求進(jìn)入,#1會被第一個和最后一個經(jīng)過,#2則是被第二和倒數(shù)第二個經(jīng)過,依次類推。
實現(xiàn)koa的實現(xiàn)有幾個最重要的點
context的保存和傳遞
中間件的管理和next的實現(xiàn)
翻看源碼我們發(fā)現(xiàn)
app.listen使用了this.callback()來生成node的httpServer的回調(diào)函數(shù)
listen(...args) { debug("listen"); const server = http.createServer(this.callback()); return server.listen(...args); }
那就再來看this. callback
callback() { const fn = compose(this.middleware); if (!this.listeners("error").length) this.on("error", this.onerror); const handleRequest = (req, res) => { const ctx = this.createContext(req, res); return this.handleRequest(ctx, fn); }; return handleRequest; }
這里用compose處理了一下this.middleware,創(chuàng)建了ctx并賦值為createContext的返回值,最后返回了handleRequest。
this.middleware看起來應(yīng)該是中間件的集合,查了下代碼,果不其然:
this.middleware = [];
use(fn) { if (typeof fn !== "function") throw new TypeError("middleware must be a function!"); if (isGeneratorFunction(fn)) { deprecate("Support for generators will be removed in v3. " + "See the documentation for examples of how to convert old middleware " + "https://github.com/koajs/koa/blob/master/docs/migration.md"); fn = convert(fn); } debug("use %s", fn._name || fn.name || "-"); this.middleware.push(fn); return this; }
拋開兼容和判斷,這段代碼只做了一件事:
use(fn) { this.middleware.push(fn); return this; }
原來當(dāng)我們app.use的時候,只是把方法存在了一個數(shù)組里。
那么compose 又是什么呢。跟蹤源碼可以看到compose來自koa-compose模塊,代碼也不多:(去掉了一些不影響主邏輯的判斷)
function compose (middleware) { return 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 if (!fn) return Promise.resolve() try { return Promise.resolve(fn(context, function next () { return dispatch(i + 1) })) } catch (err) { return Promise.reject(err) } } } }
比較關(guān)鍵的就是這個dispatch函數(shù)了,它將遍歷整個middleware,然后將context和dispatch(i + 1)傳給middleware中的方法。
return Promise.resolve(fn(context, function next () { return dispatch(i + 1) }))
這段代碼就很巧妙的實現(xiàn)了兩點:
1. 將`context`一路傳下去給中間件 2. 將`middleware`中的下一個中間件`fn`作為未來`next`的返回值
這兩點也是洋蔥模型實現(xiàn)的核心。
再往下看代碼實際上就沒有太多花樣了。
createContext和handleRequest 做的事實際上是把ctx和中間件進(jìn)行綁定,也就是第一次調(diào)用compose 返回值的地方。
createContext(req, res) { const context = Object.create(this.context); const request = context.request = Object.create(this.request); const response = context.response = Object.create(this.response); context.app = request.app = response.app = this; context.req = request.req = response.req = req; context.res = request.res = response.res = res; request.ctx = response.ctx = context; request.response = response; response.request = request; context.originalUrl = request.originalUrl = req.url; context.cookies = new Cookies(req, res, { keys: this.keys, secure: request.secure }); request.ip = request.ips[0] || req.socket.remoteAddress || ""; context.accept = request.accept = accepts(req); context.state = {}; return context; } 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); }
??
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/93712.html
摘要:任何一層報錯,都能用捕獲總結(jié)是一個非常輕量級的框架,只實現(xiàn)了中間件處理流程和對對象的封裝。其他的功能都由外部中間件提供。 koa 的中間件機制巧妙的運用了閉包和 async await 的特點,形成了一個洋蔥式的流程,和 JS 的事件流 (捕獲 -> target -> 冒泡) 相似 handleRequest(ctx, fnMiddleware) { const res ...
摘要:用法源碼由在年創(chuàng)建的科技術(shù)語。我們除去源碼校驗函數(shù)部分,從最終返回的大的來看。這個返回值無法被識別。洋蔥模型我們來看源碼源碼每個都以作為參數(shù)進(jìn)行注入,返回一個新的鏈。改變原始組數(shù),是一種副作用。 @(Redux)[|用法|源碼] Redux 由Dan Abramov在2015年創(chuàng)建的科技術(shù)語。是受2014年Facebook的Flux架構(gòu)以及函數(shù)式編程語言Elm啟發(fā)。很快,Redux因其...
摘要:實現(xiàn)的四大模塊上文簡述了源碼的大體框架結(jié)構(gòu),接下來我們來實現(xiàn)一個的框架,筆者認(rèn)為理解和實現(xiàn)一個框架需要實現(xiàn)四個大模塊,分別是封裝創(chuàng)建類構(gòu)造函數(shù)構(gòu)造對象中間件機制和剝洋蔥模型的實現(xiàn)錯誤捕獲和錯誤處理下面我們就逐一分析和實現(xiàn)。 什么是koa框架? ? ? ? ?koa是一個基于node實現(xiàn)的一個新的web框架,它是由express框架的原班人馬打造的。它的特點是優(yōu)雅、簡潔、表達(dá)力強、自由度...
摘要:實現(xiàn)的四大模塊上文簡述了源碼的大體框架結(jié)構(gòu),接下來我們來實現(xiàn)一個的框架,筆者認(rèn)為理解和實現(xiàn)一個框架需要實現(xiàn)四個大模塊,分別是封裝創(chuàng)建類構(gòu)造函數(shù)構(gòu)造對象中間件機制和剝洋蔥模型的實現(xiàn)錯誤捕獲和錯誤處理下面我們就逐一分析和實現(xiàn)。 什么是koa框架? ? ? ? ?koa是一個基于node實現(xiàn)的一個新的web框架,它是由express框架的原班人馬打造的。它的特點是優(yōu)雅、簡潔、表達(dá)力強、自由度...
閱讀 3446·2021-10-14 09:42
閱讀 2736·2021-09-08 10:44
閱讀 1309·2021-09-02 10:18
閱讀 3614·2021-08-30 09:43
閱讀 2803·2021-07-29 13:49
閱讀 3729·2019-08-29 17:02
閱讀 1585·2019-08-29 15:09
閱讀 1041·2019-08-29 11:01