摘要:是一個(gè)非常輕量的框架,里面除了和之外什么都沒有,甚至連最基本的功能都需要通過安裝其他中間件來實(shí)現(xiàn)。而的源碼同樣很簡潔,基礎(chǔ)代碼只有不到行,非常適合閱讀學(xué)習(xí)。的源碼直接從獲取,本文采用目前最新的版本。
koa是一個(gè)非常輕量的web框架,里面除了ctx和middleware之外什么都沒有,甚至連最基本的router功能都需要通過安裝其他中間件來實(shí)現(xiàn)。不過雖然簡單,但是它卻非常強(qiáng)大,僅僅依靠中間件機(jī)制就可以構(gòu)建完整的web服務(wù)。而koa的源碼同樣很簡潔,基礎(chǔ)代碼只有不到2000行,非常適合閱讀學(xué)習(xí)。
koa的源碼直接從github獲取,本文采用目前最新的2.5.1版本。
代碼結(jié)構(gòu)第一眼看到koa的源碼時(shí)候我真的懵了,反復(fù)確認(rèn)沒有看錯(cuò)之后才確信,koa源碼只有四個(gè)文件--application.js,context.js,request.js,response.js,位于項(xiàng)目的lib文件夾下。而且一看文件名基本上就能猜到每個(gè)文件是做什么的了,接下來就是打開查看里面的內(nèi)容。
koa基本啟動(dòng)流程首先看package.json里面的main,可以知道application.js是入口文件,里面是一個(gè)繼承自event模塊下的Emitter類的Application類,我們使用koa時(shí)候創(chuàng)建的app實(shí)例就是在這里定義的。
分析一個(gè)類自然要先看它的構(gòu)造函數(shù),里面重點(diǎn)的就是定義了一個(gè)數(shù)組middleware,還有三個(gè)屬性context,request,response分別為三個(gè)對(duì)象,而這三個(gè)對(duì)象就是在對(duì)應(yīng)的其他三個(gè)文件中定義的。在此我們先不看另外的文件,想想我們使用koa的時(shí)候,創(chuàng)建app實(shí)例之后,接下來就是use各種中間件了,所以直接看use方法。
use接收一個(gè)中間件函數(shù)作為參數(shù),首先做類型校驗(yàn),如果傳入的是generator,在koa2中會(huì)先通過convert進(jìn)行轉(zhuǎn)換(此處是為了兼容koa1,后續(xù)版本將移除),最后其實(shí)只做了一件事,就是把這個(gè)函數(shù)push到middleware數(shù)組中去。use方法最后會(huì)返回this,也就是koa實(shí)例本身,這就意味著我們可以實(shí)現(xiàn)鏈?zhǔn)秸{(diào)用。
設(shè)置好中間件,我們開啟koa服務(wù)的最后一步就是調(diào)用listen方法設(shè)置監(jiān)聽端口,接下來就看一下listen方法的實(shí)現(xiàn)。我們會(huì)發(fā)現(xiàn)listen更簡單,只有兩行,其實(shí)什么額外的事情也沒做,只是調(diào)用了node原生的http模塊下面的createServer方法創(chuàng)建服務(wù),listen方法設(shè)置監(jiān)聽,僅此而已。我們都知道http的createServer需要傳入一個(gè)函數(shù),這個(gè)函數(shù)在koa里面是通過調(diào)用callback方法返回的,接下來看callback的實(shí)現(xiàn)。
callback里面首先使用compose把所有的中間件變成一個(gè)函數(shù)(compose的實(shí)現(xiàn)同樣后續(xù)會(huì)詳細(xì)分析),這里會(huì)首先調(diào)用Emitter中的listenerCount方法判斷是否有error事件的監(jiān)聽器,如果沒有會(huì)為error事件注冊默認(rèn)的事件監(jiān)聽方法onerror,之后就是定義我們要的那個(gè)傳入createServer的函數(shù)了。這個(gè)函數(shù)接收req和res兩個(gè)參數(shù),之后,koa會(huì)對(duì)其做一個(gè)處理:通過調(diào)用createContext方法把req和res封裝成我們熟悉的ctx對(duì)象(createContext具體做了哪些工作接下來會(huì)說),然后把ctx和之前處理好的中間件函數(shù)fnMiddleware傳入handleRequest方法中。
handleRequest中首先先取出res,先把狀態(tài)置為404,然后對(duì)執(zhí)行中間件后的成功和失敗狀態(tài)注冊方法,失敗調(diào)用ctx.onerror捕獲異常,成功調(diào)用respond方法處理結(jié)果。這里還是用了onFinished模塊,onFinished能確保一個(gè)流在關(guān)閉、完成和報(bào)錯(cuò)時(shí)都會(huì)執(zhí)行相應(yīng)的回調(diào)函數(shù),這里把我們的異常處理函數(shù)傳入用以處理錯(cuò)誤信息。而respond方法,里面做的,就是讀取ctx信息,把數(shù)據(jù)寫入res中并響應(yīng)請(qǐng)求。至此,整個(gè)流程就完成了。
ctx的創(chuàng)建createContext里面的代碼其實(shí)特別簡單,就是創(chuàng)建了三個(gè)對(duì)象context,request,response,然后把使用ctx時(shí)候的各種東西都掛到context對(duì)象上,這樣我們就可以在ctx上面獲取到req,res等等各種信息了。創(chuàng)建context,request,response對(duì)象時(shí)候用到了當(dāng)前app類里面的三個(gè)對(duì)象,它們是通過從外部三個(gè)文件中引入的對(duì)象來創(chuàng)建的,所以接下來就看一下這三個(gè)文件中都有什么。
這三個(gè)文件導(dǎo)出的都是對(duì)象,在context中,只做了一些基礎(chǔ)方法的定義,剩下的一切屬性方法全部都使用delegate代理到request和response屬性的訪問了。而前面我們已經(jīng)知道,context上面的request和response就是通過另外的兩個(gè)文件中的對(duì)象創(chuàng)建得到的。而這兩個(gè)文件的內(nèi)容就更加簡潔了,都是我們平時(shí)使用時(shí)候訪問的屬性和方法,通過getter和setter的方式來控制上面的req和res從而實(shí)現(xiàn)對(duì)實(shí)際請(qǐng)求和響應(yīng)操作的封裝。于是整個(gè)koa核心的四個(gè)文件就徹底完成了。
compose實(shí)現(xiàn)原理與中間件機(jī)制首先做一些合法性校驗(yàn),重點(diǎn)在于最后的返回結(jié)果是一個(gè)函數(shù),這個(gè)函數(shù)就是我們上面的fnMiddleware,它同樣也有context和next兩個(gè)參數(shù),在其內(nèi)部采用index變量記錄當(dāng)前處理到哪個(gè)中間件,然后從第一個(gè)開始調(diào)用dispatch方法。首先會(huì)判斷當(dāng)前傳入?yún)?shù)與index的關(guān)系,如果在一個(gè)中間件內(nèi)多次調(diào)用next,會(huì)出現(xiàn)參數(shù)小于index的情況,此時(shí)就會(huì)報(bào)錯(cuò)。之后把當(dāng)前中間件從數(shù)組中取出來,每次執(zhí)行時(shí)會(huì)把ctx和next傳入,next中調(diào)用dispatch,參數(shù)為下一個(gè)位置,這樣就會(huì)按順序把中間件添加進(jìn)來,最后當(dāng)i等于中間件數(shù)組長度時(shí)候,也就是沒有其他中間件了,那么執(zhí)行一開始傳入的next參數(shù),如果fn不存在,返回空的promise。當(dāng)中心執(zhí)行完,也就是前一個(gè)中間件的next執(zhí)行完,自然會(huì)觸發(fā)await向下執(zhí)行,之后執(zhí)行權(quán)會(huì)反向順序返回,最終組合的結(jié)果就是先從外向里,再從里向外,就是我們熟知的洋蔥圈模型。
錯(cuò)誤處理機(jī)制koa的錯(cuò)誤處理機(jī)制也很有特點(diǎn),我們只要監(jiān)聽koa實(shí)例的error事件,就可以統(tǒng)一處理所有的錯(cuò)誤。我們在前面提到過,調(diào)用fnMiddleware失敗后會(huì)被統(tǒng)一的onerror方法捕獲,這個(gè)方法是對(duì)應(yīng)到ctx上的onerror方法,我們來看一下里面的實(shí)現(xiàn),里面非常重要的一行就是this.app.emit("error", err, this);,由于我們的koa是繼承自event,所以可以派發(fā)出一個(gè)error事件,我們只要處理該事件即可。而前面在中間件處理中,如果發(fā)生錯(cuò)誤就會(huì)reject,自然可以被catch捕獲到。
以上,就是koa基本核心模塊的流程,原理很簡單,但是配合各種中間件,koa完全可以實(shí)現(xiàn)一個(gè)功能完整web server。
本文原創(chuàng),愿意分享但轉(zhuǎn)載請(qǐng)?zhí)崆案嬷辔恼虏榭次业闹黜?,感謝閱讀,如錯(cuò)誤歡迎指正。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/94819.html
摘要:引言最近空閑時(shí)間讀了一下的源碼在閱讀的源碼的過程中,我的感受是代碼簡潔思路清晰不得不佩服大神的水平。調(diào)用的時(shí)候就跟有區(qū)別使用必須使用來調(diào)用除了上面的的構(gòu)造函數(shù)外,還暴露了一些公用的,比如兩個(gè)常見的,一個(gè)是,一個(gè)是。 引言 最近空閑時(shí)間讀了一下Koa2的源碼;在閱讀Koa2(version 2.2.0)的源碼的過程中,我的感受是代碼簡潔、思路清晰(不得不佩服大神的水平)。下面是我讀完之后...
摘要:實(shí)現(xiàn)的四大模塊上文簡述了源碼的大體框架結(jié)構(gòu),接下來我們來實(shí)現(xiàn)一個(gè)的框架,筆者認(rèn)為理解和實(shí)現(xiàn)一個(gè)框架需要實(shí)現(xiàn)四個(gè)大模塊,分別是封裝創(chuàng)建類構(gòu)造函數(shù)構(gòu)造對(duì)象中間件機(jī)制和剝洋蔥模型的實(shí)現(xiàn)錯(cuò)誤捕獲和錯(cuò)誤處理下面我們就逐一分析和實(shí)現(xiàn)。 什么是koa框架? ? ? ? ?koa是一個(gè)基于node實(shí)現(xiàn)的一個(gè)新的web框架,它是由express框架的原班人馬打造的。它的特點(diǎn)是優(yōu)雅、簡潔、表達(dá)力強(qiáng)、自由度...
摘要:實(shí)現(xiàn)的四大模塊上文簡述了源碼的大體框架結(jié)構(gòu),接下來我們來實(shí)現(xiàn)一個(gè)的框架,筆者認(rèn)為理解和實(shí)現(xiàn)一個(gè)框架需要實(shí)現(xiàn)四個(gè)大模塊,分別是封裝創(chuàng)建類構(gòu)造函數(shù)構(gòu)造對(duì)象中間件機(jī)制和剝洋蔥模型的實(shí)現(xiàn)錯(cuò)誤捕獲和錯(cuò)誤處理下面我們就逐一分析和實(shí)現(xiàn)。 什么是koa框架? ? ? ? ?koa是一個(gè)基于node實(shí)現(xiàn)的一個(gè)新的web框架,它是由express框架的原班人馬打造的。它的特點(diǎn)是優(yōu)雅、簡潔、表達(dá)力強(qiáng)、自由度...
摘要:若大于時(shí),將賦予,此時(shí)與相等。通過源碼分析,我們知道了的核心思想建立于中間件機(jī)制,它是一個(gè)設(shè)計(jì)十分簡潔巧妙的框架,擴(kuò)展性極強(qiáng),就是建立于之上的上層框架。 Koa是一款設(shè)計(jì)優(yōu)雅的輕量級(jí)Node.js框架,它主要提供了一套巧妙的中間件機(jī)制與簡練的API封裝,因此源碼閱讀起來也十分輕松,不論你從事前端或是后端研發(fā),相信都會(huì)有所收獲。 目錄結(jié)構(gòu) 首先將源碼下載到本地,可以看到Koa的源碼只包含...
閱讀 2162·2023-04-26 00:38
閱讀 1945·2021-09-07 10:17
閱讀 898·2021-09-02 15:41
閱讀 648·2021-08-30 09:45
閱讀 556·2019-08-29 17:25
閱讀 3225·2019-08-29 15:07
閱讀 2201·2019-08-29 12:52
閱讀 3747·2019-08-26 13:35