摘要:本文來自心譚博客深入源碼架構設計前端面試設計模式手冊教程實戰等更多專題,請來導航頁領取食用所有系列文章都放在了。歡迎交流和最近讀了的源碼,理清楚了架構設計與用到的第三方庫。
本文來自《心譚博客·深入koa源碼:架構設計》
前端面試、設計模式手冊、Webpack4教程、NodeJs實戰等更多專題,請來導航頁領取食用
所有系列文章都放在了Github。歡迎交流和Star ?? ヽ(°▽°)ノ ?
最近讀了 koa 的源碼,理清楚了架構設計與用到的第三方庫。本系列將分為 3 篇,分別介紹 koa 的架構設計和 3 個核心庫的原理,最終會手動實現一個簡易的 koa。
koa 的實現都在倉庫的lib目錄下,如下圖所示,只有 4 個文件:
對于這四個文件,根據用途和封裝邏輯,可以分為 3 類:req 和 res,上下文以及 application。
req 和 res對應的文件是:request.js 和 response.js。分別代表著客戶端請求信息和服務端返回信息。
這兩個文件在實現邏輯上完全一致。對外暴露都是一個對象,對象上的屬性都使用了getter或setter來實現讀寫控制。
上下文對應的文件是:context.js。存了運行環境的上下文信息,例如cookies。
除此之外,因為request和response都屬于上下文信息,所以通過delegate.js庫來實現了對request.js和response.js上所有屬性的代理。例如以下代碼:
/** * Response delegation. */ delegate(proto, "response") .method("attachment") .method("redirect"); /** * Request delegation. */ delegate(proto, "request") .method("acceptsLanguages") .method("acceptsEncodings");
使用代理的另外一個好處就是:更方便的訪問 req 和 res 上的屬性。比如在開發 koa 應用的時候,可以通過ctx.headers來讀取客戶端請求的頭部信息,不需要寫成ctx.res.headers了(這樣寫沒錯)。
注意:req 和 res 并不是在context.js中被綁定到上下文的,而是在application被綁定到上下文變量ctx中的。原因是因為每個請求的 req/res 都不是相同的。
Application對應的文件是: application.js。這個文件的邏輯是最重要的,它的作用主要是:
給用戶暴露服務啟動接口
針對每個請求,生成新的上下文
處理中間件,將其串聯
對外暴露接口使用 koa 時候,我們常通過listen或者callback來啟動服務器:
const app = new Koa(); app.listen(3000); // listen啟動 http.createServer(app.callback()).listen(3000); // callback啟動
這兩種啟動方法是完全等價的。因為listen方法內部,就調用了callback,并且將它傳給http.createServer。接著看一下callback這個方法主要做了什么:
調用koa-compose將中間件串聯起來(下文再講)。
生成傳給http.createServer()的函數,并且返回。
http.createServer傳給函數參數的請求信息和返回信息,都被這個函數拿到了。并且傳給createContext方法,生成本次請求的上下文。
將生成的上下文傳給第 1 步生成的中間件調用鏈,這就是為什么我們在中間件處理邏輯的時候能夠訪問ctx
生成新的上下文這里上下文的方法對應的是createContext方法。這里我覺得更像語法糖,是為了讓 koa 使用者使用更方便。比如以下這段代碼:
// this.request 是 request.js 暴露出來的對象,將其引用保存在context.request中 // 用戶可以直接通過 ctx.屬性名 來訪問對應屬性 const request = (context.request = Object.create(this.request)); // 這個req是本次請求信息,是由 http.createServer 傳遞給回調函數的 context.req = request.req = response.req = req;
讀到這里,雖然可以解釋 ctx.headers 是 ctx.request.headers 的語法糖這類問題。但是感覺怪怪的。就以這個例子,ctx.headers 訪問的是 ctx.reqeust 上的 headers,而不是本次請求信息上的headers。本次請求信息掛在了ctx.req上。
讓我們再回到reqeust.js的源碼,看到了headers的 getter 實現:
get headers() { return this.req.headers; }
ok,看來這里的this就是指的上下文環境咯。那么肯定是在application.js中某個地方改變了this的指向。果然,在application.js的構造函數中可以看到:
this.request = Object.create(request);
application 實例上的 request 被傳遞給了 context.request,此時 this 自然指向了 context。
可以看到,koa 為了讓開發者使用方便,在上下文上做了很多工作。
中間件機制中間件的設計是 koa 最重要的部分,實現上用到了koa-compose庫來串聯中間件,形成“洋蔥模型”。關于這個庫,放在第二篇關于 koa 核心庫的介紹中說明。
application 中處理中間件的函數是use和handleRequest:
use函數:傳入async/await函數,并將其放入 application 實例上的middleware數組中。如果傳入是 generator,會調用koa-conver庫將其轉化為async/await函數。
handleRequest(ctx, fnMiddleware)函數:傳入的fnMiddleware是已經串聯好的中間件,函數所做的工作就是再其后再添加一個返回給客戶端的函數和錯誤處理函數。返回給客戶端的函數其實就是respond函數,里面通過調用res.end()來向客戶端返回信息,整個流程就走完了。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/104916.html
摘要:最近讀了的源碼,理清楚了架構設計與用到的第三方庫。本系列將分為篇,分別介紹的架構設計和個核心庫,最終會手動實現一個簡易的。本文來自心譚博客深入源碼核心庫原理所有系列文章都放在了。這一段邏輯封裝在了核心庫里面。 最近讀了 koa2 的源碼,理清楚了架構設計與用到的第三方庫。本系列將分為 3 篇,分別介紹 koa 的架構設計和 3 個核心庫,最終會手動實現一個簡易的 koa。這是系列第 2...
摘要:閱讀好的框架的源碼有很多好處,從大神的視角去理解整個框架的設計思想。使用其實某個框架閱讀源碼的時候,首先我們要會去用這個框架,因為用了我們才知道,某個是怎么用,哪里有坑,哪里設計的精妙。 閱讀好的框架的源碼有很多好處,從大神的視角去理解整個框架的設計思想。大到架構設計,小到可取的命名風格,還有設計模式、實現某類功能使用到的數據結構和算法等等。 使用koa 其實某個框架閱讀源碼的時候,首...
摘要:閱讀好的框架的源碼有很多好處,從大神的視角去理解整個框架的設計思想。使用其實某個框架閱讀源碼的時候,首先我們要會去用這個框架,因為用了我們才知道,某個是怎么用,哪里有坑,哪里設計的精妙。 閱讀好的框架的源碼有很多好處,從大神的視角去理解整個框架的設計思想。大到架構設計,小到可取的命名風格,還有設計模式、實現某類功能使用到的數據結構和算法等等。 使用koa 其實某個框架閱讀源碼的時候,首...
摘要:感謝大神的免費的計算機編程類中文書籍收錄并推薦地址,以后在倉庫里更新地址,聲音版全文狼叔如何正確的學習簡介現在,越來越多的科技公司和開發者開始使用開發各種應用。 說明 2017-12-14 我發了一篇文章《沒用過Node.js,就別瞎逼逼》是因為有人在知乎上黑Node.js。那篇文章的反響還是相當不錯的,甚至連著名的hax賀老都很認同,下班時讀那篇文章,竟然坐車的還坐過站了。大家可以很...
摘要:感謝大神的免費的計算機編程類中文書籍收錄并推薦地址,以后在倉庫里更新地址,聲音版全文狼叔如何正確的學習簡介現在,越來越多的科技公司和開發者開始使用開發各種應用。 說明 2017-12-14 我發了一篇文章《沒用過Node.js,就別瞎逼逼》是因為有人在知乎上黑Node.js。那篇文章的反響還是相當不錯的,甚至連著名的hax賀老都很認同,下班時讀那篇文章,竟然坐車的還坐過站了。大家可以很...
閱讀 3482·2021-09-06 15:13
閱讀 1531·2021-09-02 10:19
閱讀 2477·2019-08-30 15:52
閱讀 924·2019-08-29 15:25
閱讀 1570·2019-08-26 18:36
閱讀 499·2019-08-26 13:23
閱讀 1337·2019-08-26 10:46
閱讀 3505·2019-08-26 10:41