Koa2 还有多久取代 Express
前言
Koa 是運(yùn)行在 Node.js 中的 web 服務(wù)框架,小而美。
Koa2 是 Koa 框架的最新版本,Koa3 還沒有正式推出,Koa1 正走在被替換的路上。
Koa2 與 Koa1 的最大不同,在于 Koa1 基于 co 管理 Promise/Generator 中間件,而 Koa2 緊跟最新的 ES 規(guī)范,支持到了 Async Function(Koa1 不支持),兩者中間件模型表現(xiàn)一致,只是語法底層不同。
Koa2 正在蠶食 Express 的市場份額,最大的原因是 Javascript 的語言特性進(jìn)化,以及 Chrome V8 引擎的升級,賦予了 Node.js 更大的能力,提升開發(fā)者的編程體驗(yàn),滿足開發(fā)者靈活定制的場景以及對于性能提升的需求,蠶食也就水到渠成,2018 年開始,Koa2 會(huì)超越 Express 成為本年最大普及量的 Node.js 框架。
以上就是 Koa2 的現(xiàn)狀,以及它的趨勢,站在 2018 年的節(jié)點(diǎn)來看,Koa2 的學(xué)習(xí)大潮已經(jīng)到來,那么如果要掌握 Koa2,需要去學(xué)習(xí)它的哪些知識(shí)呢,這些知識(shí)跟 Node.js 以及語言規(guī)范有什么關(guān)系,它的內(nèi)部組成是如何的,運(yùn)行機(jī)制怎樣,定制拓展是否困難,以及它的三方庫生態(tài)如何,應(yīng)用場景有哪些,跟前端有如何結(jié)合等等,這些問題本文將做簡要的探討,Koa2 詳細(xì)的代碼案例和深度剖析見這里?。
備注:如下提到的 Koa 均指代 Koa 2.x 版本關(guān)于作者 TJ
了解過 TJ 的童鞋都知道,他以驚為天人的代碼貢獻(xiàn)速度、源源不斷的開發(fā)熱情和巧奪天工的編程模型而推動(dòng)整個(gè) Node.js/NPM 社區(qū)大步邁進(jìn),稱為大神毫不過分,而大神的腦回路,向來與凡人不同。
關(guān)于大神的傳說有很多,最有意思的是在國外著名程序員論壇 reddit 上,有人說,TJ 從來就不是一個(gè)人,一個(gè)人能有這么高效而瘋狂的代碼產(chǎn)出實(shí)在是太讓人震驚了,他背后一定是一個(gè)團(tuán)隊(duì),因?yàn)樗麖膩矶疾粎⒓蛹夹g(shù)會(huì)議,也不見任何人,而最后 TJ 離開 Node 社區(qū)去轉(zhuǎn)向 Go,這種做事方式非常谷歌,所以 TJ 是谷歌的一個(gè)招牌,大家眾說紛紜,吵的不可開交,不過有一點(diǎn)大家都是達(dá)成共識(shí)的,那就是非??隙ê透兄x他對于 Nodejs 社區(qū)的貢獻(xiàn)和付出。
Express 的架構(gòu)和中間件模型
聊 Koa 之前,先對比下 Express,在 Express 里面,不同時(shí)期的代碼組織方式雖然大為不同,比如早期是全家桶各種路由、表單解析都囊括到一個(gè)項(xiàng)目中,中后期做了大量的拆分,將大部分模塊都獨(dú)立出來官方自行維護(hù),或者是采用社區(qū)其他開發(fā)者提供的中間件模塊,但縱觀 Express 多年的歷程,他依然是相對大而全,API 較為豐富的框架,并且它的整個(gè)中間件模型是基于 callback 回調(diào),而 callback 常年被人詬病。
對于一個(gè) web 服務(wù)框架來說,它的核心流程,就是在整個(gè) HTTP 進(jìn)入到流出的過程中,從它的流入數(shù)據(jù)上采集所需要的參數(shù)素材,再向流出的數(shù)據(jù)結(jié)構(gòu)上附加期望素材,無論是一個(gè)靜態(tài)文件還是 JSON 數(shù)據(jù),而在采集和附加的過程中,需要各個(gè)中間件大佬的參與,有的干的是記錄日志的活兒,有的干的是解析表單的活兒,有的則是管理會(huì)話,既然是大佬,一般都脾氣大,你不安排好他們的注冊順序,不通過一種機(jī)制管理他們的入場退場順序,他們不僅不好好配合,還可能砸了你的場子。
那么 Express 里面,首先就是對于 HTTP 這個(gè)大家伙的管理(其他協(xié)議先不涉及),管理這個(gè)大家伙,Express 祭出了三件,哦不,其實(shí)是四件法寶。
首先是通過 express() 拿到的整個(gè)服務(wù)器運(yùn)行實(shí)例,這個(gè)實(shí)例相當(dāng)于是一個(gè)酒店,而你就是來訪的客人 - HTTP 請求,酒店負(fù)責(zé)你一切需求,做到你滿意。
在酒店里面,還有兩個(gè)工作人員,一個(gè)是 req(request) 負(fù)責(zé)接待你的叫阿來吧,還有一個(gè)送你離開的狠角色 - res(response),叫阿去吧,阿來接待到你進(jìn)酒店,門口的攝像頭會(huì)你拍照(Log 記錄來去時(shí)間,你的特征),收集你的指紋(老會(huì)員識(shí)別),引領(lǐng)你去前臺(tái)簽到(獲取你的需求,比如你要拿走屬于你的一套西服),然后酒店安排你到房間休息(等待響應(yīng)),里面各種后勤人員忙忙碌碌接待不同的客人,其中有一個(gè)是幫你取西服的,取了后,交給阿來,阿來再把西服穿你身上,同時(shí)還可能幫你裝飾一番,比如給你帶個(gè)帽子(加個(gè)自定義頭),然后送你出門,門口的攝像頭還會(huì)拍你一下,就知道了酒店服務(wù)你的時(shí)間......實(shí)在編不下去了,想用物理世界的案例來對應(yīng)到程序世界是蠻難的,嚴(yán)謹(jǐn)度不夠,不過幫新手同學(xué)留下一個(gè)深刻印象倒是可取的。
Express 源碼簡要分析
上面酒店的 4 件法寶,其實(shí)就是服務(wù)器運(yùn)行實(shí)例,req 請求對象,res 響應(yīng)對象和中間件 middlewares,剛才負(fù)責(zé)照相的,簽到的,分析需求的其實(shí)都是中間件,一個(gè)一個(gè)濾過去,他們根據(jù)自己的規(guī)則進(jìn)行采集、分析、轉(zhuǎn)化和附加,把這個(gè) HTTP 客人,從頭到腳捏一遍,客人就舒舒服服的離開了。
中間件是眾多 web 框架中比較核心的概念,它們可以根據(jù)不同的場景,來集成到框架中,增強(qiáng)框架的服務(wù)能力,而框架則需要提供一套機(jī)制來保證中間件是有序執(zhí)行,這個(gè)機(jī)制在不同的框架中則大為不同,在 Express 里面,我們通過 use(middlewares()) 逐個(gè) use 下去,use 的順序和規(guī)則都由 express 自身控制。
在 express/express.js 中,服務(wù)器運(yùn)行實(shí)例 app 通過 handle 來把 Nodejs 的 req 和 res 傳遞給 handle 函數(shù),賦予 handle 對于內(nèi)部對象的控制權(quán):
而在 express/application.js 中,拿到控制權(quán)的 handle 又把請求響應(yīng)和回調(diào),繼續(xù)分派給了 express 的核心路由模塊,也就是 router:
app.handle = function handle (req, res, callback) {var router = this._routervar done = callback || finalhandler(req, res, {env: this.get('env'),onerror: logerror.bind(this)})router.handle(req, res, done) }這里的 router.handle 就持有到了 req, res 對象,可以理解為,express 把 Nodejs 監(jiān)聽到的請求三要素(req, res, cb) 下放給了內(nèi)部的路由模塊 router。
然后繼續(xù)回到剛才 use(middlewares(),Express 每一次 use 中間件,都會(huì)把這個(gè)中間件也交給 router:
而 router 里面,有很重要一個(gè)概念,就是 layer 層,可以理解為中間件堆疊的層,一層層堆疊起來:
var layer = new Layer(path, {sensitive: this.caseSensitive,strict: false,end: false }, fn) this.stack.push(layer)以上是偽代碼(刪減了大部分),可以看做是 express 在啟動(dòng)運(yùn)行的時(shí)候,注冊好了一個(gè)中間件函數(shù)棧,里面堆疊好了待被調(diào)用的中間件,一旦請求進(jìn)來,就會(huì)被 router handle 來處理:
proto.handle = function handle(req, res, out) {next()function next(err) {var layervar routeself.process_params(layer, paramcalled, req, res, function (err) {if (route) {return layer.handle_request(req, res, next)}trim_prefix(layer, layerError, layerPath, path)})}function trim_prefix(layer, layerError, layerPath, path) {if (layerError) {layer.handle_error(layerError, req, res, next)} else {layer.handle_request(req, res, next)}} }handle 里面的 next 是整個(gè)中間件棧能夠轉(zhuǎn)起來的關(guān)鍵,在所有的中間件里面,都要執(zhí)行這個(gè) next,從而把當(dāng)前的控制權(quán)以回調(diào)的方式往下面?zhèn)鬟f。
但是問題就是這種機(jī)制在最初的時(shí)候,如果沒有事件的配合,是很難做到原路進(jìn)去,再順著原路回去,相當(dāng)于是每個(gè)中間件都被來回濾了 2 遍,賦予中間件更靈活的控制權(quán),這就是掣肘 Express 的地方,也是 Express 市場一定會(huì)被 Koa 蠶食的重要原因。
具體 Express 的代碼比這里描述的要復(fù)雜好幾倍,大家有興趣可以去看源碼,應(yīng)該會(huì)有更多的收獲,如果沒有 Koa 這種框架存在的話,Express 的內(nèi)部實(shí)現(xiàn)用精妙形容絕對不為過,只是這種相對復(fù)雜一些的內(nèi)部中間件機(jī)制,未必符合所有人的口味,也說明了早些年限于 JS 的能力,想要做一些流程雙向控制多么困難。
關(guān)于 Express 就分析到這里,這不是本文的重點(diǎn),了解它內(nèi)部的復(fù)雜度以及精妙而復(fù)雜都實(shí)現(xiàn)就可以了,因?yàn)檫@是特定歷史階段的歷史產(chǎn)物,有它特定的歷史使命。
早期的 Koa 模型 - 我們不一樣
得益于大神非同尋常的腦回路,Koa 從一開始就選擇了跟 Express 完全不同的架構(gòu)方向,上面 Express 的部分大家沒看懂也沒關(guān)系,因?yàn)?Koa 這里的處理,會(huì)讓你瞬間腦回路清晰。
首先要明白,Koa 與 Express 是在做同樣事情上的不同實(shí)現(xiàn),所以意味著他倆對外提供的能力大部分是相同的,這部分不贅述,我們看不同的地方:
Koa 內(nèi)部也有幾個(gè)神行太保,能力較大,首先 new Koa() 出來的服務(wù)器運(yùn)行實(shí)例,它像青蛙一樣,張大嘴吞食所有的請求,通過它可以把服務(wù)真正跑起來,跟 Express 一樣,這個(gè)就跳過不提了,重點(diǎn)是它的 context,也就是 ctx,這貨上面有很多引用,最核心的是 request 和 response,這倆可以對應(yīng)到 Express 兩個(gè)對立的 req 和 res,在 Koa 里面,把它倆都集中到 ctx 里面進(jìn)行管理,分別通過 ctx.request 和 ctx.reponse 進(jìn)行直接訪問,原來 Express 兩個(gè)獨(dú)立對象做的事情,現(xiàn)在一個(gè) ctx 就夠了,上下文對象都在他手中,想要聯(lián)系誰就能聯(lián)系誰。
其次是它的中間件機(jī)制,Koa 真正的魅力所在,先看段代碼:
大家可以把這 22 行代碼跑起來,瀏覽器里訪問 localhost:2333 就能看到代碼的執(zhí)行路徑,一個(gè) HTTP 請求,從進(jìn)入到流出,是兩次穿透,每一個(gè)中間件都被穿透兩次,這個(gè)按照次序的正向進(jìn)入和反向穿透并不是必選項(xiàng),而是 Koa 輕松具備的能力,同樣的能力,在 Express 里面實(shí)現(xiàn)反而很費(fèi)勁。
Koa2 源碼簡要分析
想要了解上面提到的能力,就要看下 Koa 核心的代碼:
同樣是 app.use(middlewares()),在 koa/application.js 里面,每一個(gè)中間件同樣被壓入到一個(gè)數(shù)組中:
在服務(wù)器啟動(dòng)的時(shí)候,建立監(jiān)聽,同時(shí)注冊回調(diào)函數(shù):
listen(...args) {server = http.createServer(this.callback()).listen(...args) }回調(diào)函數(shù)里面,返回了 (req, res) 給 Node.js 用來接收請求,在它內(nèi)部,首先基于 req, res 創(chuàng)建出來 ctx,就是那個(gè)同時(shí)能管理 request 和 response 的家伙,重點(diǎn)是上面壓到數(shù)組里面的 middlewares 被 compose 處理后,就扔給了 handleRequest:
callback() {const fn = compose(this.middleware)return handleRequest = (req, res) => {const ctx = this.createContext(req, res)return this.handleRequest(ctx, fn)} }compose 就是 koa-compose,簡單理解為通過它,以遞歸的方式實(shí)現(xiàn)了 Promise 的鏈?zhǔn)綀?zhí)行,因?yàn)槲覀兌贾?#xff0c; async function 本質(zhì)上會(huì)返回一個(gè) Promise,這里 compose 跳過不說了,繼續(xù)去看 handleRequest:
handleRequest(ctx, fnMiddleware) {return fnMiddleware(ctx).then(respond(ctx)) }實(shí)在是簡潔的不像實(shí)力派,請求進(jìn)來后,會(huì)把可以遞歸調(diào)用的中間件數(shù)組都執(zhí)行一遍,每個(gè)中間件都能拿到 ctx,同時(shí),因?yàn)?async function 的語法特性,可以中間件中,把執(zhí)行權(quán)交給后面的中間件,這樣逐層逐層交出去,最后再逐層逐層執(zhí)行回來,就達(dá)到了請求沿著一條路進(jìn)入,響應(yīng)沿著同樣的一條路反向返回的效果。
借用官方文檔的一張圖來表達(dá)這個(gè)過程:
我知道這張圖還不夠,再祭出官方的第二張圖,著名的洋蔥模型:
Koa2 要學(xué)習(xí)什么
從上面的對比,我們其實(shí)就發(fā)現(xiàn)了 Koa2 獨(dú)具魅力的地方,這些魅力一方面跟框架設(shè)計(jì)理念有關(guān),一方面跟語言特性有關(guān),語言特性,無外乎下面幾個(gè):
- 箭頭函數(shù)
- Promise 規(guī)范
- 迭代器生成器函數(shù)執(zhí)行原理
- 異步函數(shù) Async Function
- 以及 Koa2 的應(yīng)用上下文 ctx 的常用 API(也即它的能力)
- koa-compose 工具函數(shù)的遞歸特征
- 中間件執(zhí)行的進(jìn)出順序和用法
這些都是基礎(chǔ)性的值得學(xué)習(xí)的,這些知識(shí)跟著語言規(guī)范有著非常親近的關(guān)系,所以意味著學(xué)會(huì)這些以后,也需要去到 ES6/7/8 里面挑選更多的語法特性,早早入坑學(xué)習(xí),限于篇幅本文均不再探討,上面的基礎(chǔ)知識(shí)學(xué)習(xí)如果有興趣,可以跟著?Koa2解讀+數(shù)據(jù)抓取+實(shí)戰(zhàn)電影網(wǎng)站?了解更多實(shí)戰(zhàn)姿勢。
Koa2 和 Express 到底如何選擇
能不能來個(gè)痛快話?其實(shí)可以的,選 Koa2 吧,2018 年了,不用等了。
同時(shí)一定非它不可么,其實(shí)也不是,我們可以更加客觀的看待選擇問題,再梳理下思緒:
Koa 是基于新的語法特性,實(shí)現(xiàn)了 Promise 鏈傳遞,錯(cuò)誤處理更友好,Koa 不綁定任何中間件,是干干凈凈的裸框架,需要什么就加什么,Koa 對流支持度很好,通過上下文對象的交叉引用讓內(nèi)部流程與請求和響應(yīng)串聯(lián)的更緊湊,如果 Express 是大而全,那么 Koa 就是小而精,二者定位不同,只不過 Koa 擴(kuò)展性非常好,稍微組裝幾個(gè)中間件馬上就能跟 Express 匹敵,代碼質(zhì)量也更高,設(shè)計(jì)理念更先進(jìn),語法特性也更超前。
這是站在用戶的角度比較的結(jié)果,如果站在內(nèi)部實(shí)現(xiàn)的角度,Koa 的中間件加載和執(zhí)行機(jī)制跟 Express 是截然不同的,他倆在這一點(diǎn)上的巨大差別也導(dǎo)致了一個(gè)項(xiàng)目可以完全走向兩種不同的中間件設(shè)計(jì)和實(shí)現(xiàn)方式,不過往往我們是作為框架的使用者,業(yè)務(wù)的開發(fā)者來使用的,那么對于 Nodejs 的用戶來說,Express 能滿足你的,Koa 都可以滿足你,Express 讓你爽的,Koa 可以讓你更爽。
這也是為什么,阿里的企業(yè)級框架 Eggjs 底層是 Koa 而不是 Express,360 公司的大而全的 thinkjs 底層也是 Koa,包括沃爾瑪?shù)?hapi 雖然沒有用 Koa,但是他的核心開發(fā)者寫博客說,受到 Koa 的沖擊和影響, 也要升級到 async function,保持對語法的跟進(jìn),而這些都是 Koa 已經(jīng)做好了整個(gè)底子,任何上層架構(gòu)變得更簡單了。
大家在選用 Express 的時(shí)候,或者從 Express 升級到 Koa 的時(shí)候,其實(shí)不用太糾結(jié),只要成本允許,都可以使用,如果實(shí)現(xiàn)成本過高,那么用 Express 也沒問題的,遇到其他新項(xiàng)目的時(shí)候,沒有了歷史包袱,在用 Koa 也不遲。
Koa 運(yùn)行機(jī)制和 Nodejs 事件循環(huán)
其實(shí)通過上面的篇幅,我們對于內(nèi)部組成基本了解了,運(yùn)行機(jī)制其實(shí)就是中間件執(zhí)行機(jī)制,而定制拓展性,我們上面提到了 Eggjs 和 Thinkjs 已經(jīng)充分證明了它可定制的強(qiáng)大潛力,這里我們主要聊下跟運(yùn)行機(jī)制相關(guān)的,一個(gè)是 Koajs 自身,另外的一個(gè)是通過它向下到 Node.js 底層,它的運(yùn)行機(jī)制是怎樣的,這塊涉及到 Libuv 的事件循環(huán),如果不了解的話,很難在 Node.js 這顆技能樹上再進(jìn)一臺(tái)階,所以它也非常重要。
而 Libuv 的事件循環(huán),本質(zhì)上決定了 Node.js 的異步屬性和異步能力,提到異步,我們都知道 Node.js 的異步非阻塞 IO,但是大家對于 同步異步以及阻塞非阻塞,都有了自己的理解,說到異步 IO,其實(shí)往往我們說的是操作系統(tǒng)所提供的異步 IO 能力,那首先什么是 IO,說白了,就是數(shù)據(jù)進(jìn)出,人機(jī)交互的時(shí)候,我們會(huì)把鍵盤鼠標(biāo)這些外設(shè)看做是 Input,也就是輸入,對應(yīng)到主機(jī)上,會(huì)有專門流入數(shù)據(jù)或者信號的物理接口,顯示器作為一個(gè)可視化的外設(shè),對應(yīng)到主機(jī)上,會(huì)有專門的輸出數(shù)據(jù)的接口,這就是生活中我們可見的 IO 能力,這個(gè)接口再向下,會(huì)進(jìn)入到操作系統(tǒng)這個(gè)層面,在操作系統(tǒng)層面,會(huì)提供諸多的能力,比如磁盤讀寫,DNS 查詢,數(shù)據(jù)庫連接,網(wǎng)絡(luò)請求接收與返回等等,在不同的操作系統(tǒng)中,他們表現(xiàn)出來的特征也不一致,有的是純異步的,非阻塞的,有的是同步的阻塞的,無論怎么樣,我們都可以把這些 IO 看做是上層應(yīng)用和下層系統(tǒng)之間的數(shù)據(jù)交互,上層依賴于下層,上層也可以進(jìn)一步對這些能力進(jìn)行定制改造,如果這個(gè)交互是異步的非阻塞的,那么這種就是 異步 IO 模型,如果是同步的阻塞的,那么就是同步 IO 模型。
在 Nodejs 里面,我們可以拿文件讀寫為例,Koa 只是一個(gè)上層的 web 應(yīng)用服務(wù)框架而已,它所有與操作系統(tǒng)之家的溝通能力,都建立在 Node.js 整個(gè)的通信服務(wù)模型的基礎(chǔ)之上,Nodejs 提供了 filesystem 也就是 fs 這個(gè)模塊,模塊中提供了文件讀寫的接口,比如 readFile 這個(gè)異步的接口,它就是一個(gè)典型的異步 IO 接口,反之 readFileSync 就是一個(gè)阻塞的同步 IO 接口,以這個(gè)來類推,我們站在上層的 web 服務(wù)這個(gè)層面,就很容易理解 Node.js 的異步非阻塞模型,異步 IO 能力。
那么 Node.js 的異步能力又是建立在 Libuv 這一層的幾個(gè)階段上的,什么?還有階段?
是的,Node.js 的底層除了解釋和執(zhí)行 JS 代碼的 Chrome V8 虛擬機(jī),還有一大趴兒就是 Libuv,它跟操作系統(tǒng)交互,封裝了不同平臺(tái)的諸多接口,相當(dāng)于抹平了操作系統(tǒng)的異步差異帶來的兼容性,讓 Node.js 對外提供一致的同異步 API,而 Libuv 的幾個(gè)階段,便是對于單線程的 JS 最有利的輔助實(shí)現(xiàn),所有的異步都可以看做是任務(wù),任務(wù)是耗時(shí)的,libuv 把這些任務(wù)分成不同類型,分到不同階段,有他們各自的執(zhí)行規(guī)律和執(zhí)行優(yōu)先級。
大家可以先預(yù)測下下面這段代碼的執(zhí)行結(jié)果:
const EventEmitter = require('events') class EE extends EventEmitter {} const yy = new EE() yy.on('event', () => console.log('粗大事啦')) setTimeout(() => console.log('0 毫秒后到期的定時(shí)器回調(diào)'), 0) setTimeout(() => console.log('100 毫秒后到期的定時(shí)器回調(diào)'), 100) setImmediate(() => console.log('immediate 立即回調(diào)')) process.nextTick(() => console.log('process.nextTick 的回調(diào)')) Promise.resolve().then(() => {yy.emit('event')process.nextTick(() => console.log('process.nextTick 的回調(diào)'))console.log('promise 第一次回調(diào)') }) .then(() => console.log('promise 第二次回調(diào)'))你會(huì)發(fā)現(xiàn)你踏入了一個(gè) 【美好】 的世界,這就是我們通過了解 Koa 以后,如果想要繼續(xù)往下學(xué)習(xí),需要掌握的知識(shí),這塊知識(shí)才是真正的干貨,一言半語的確說不清楚,我們保留思路往下走。
Koa2 的三方庫生態(tài)如何
在 Koa1 時(shí)代和 Koa2 剛出的時(shí)候,的確它的三方庫不多,需要自己動(dòng)手包裝,甚至還有 koa-convert 專門干這個(gè)活兒,把 1 代 koa 中間件轉(zhuǎn)成可以兼容 2 代 koa 可以兼容的形式。
但是時(shí)至今日,Koa2 的生態(tài)已經(jīng)相當(dāng)完善了,尤其在 2018 年隨著更多開發(fā)者切入到 Koa2 中,將會(huì)有大批量的業(yè)界優(yōu)秀模塊庫進(jìn)入到 Koa2 的大池子中,大家會(huì)發(fā)現(xiàn)可選擇的越來越多,所以他的生態(tài)沒問題。
跟前端如何結(jié)合
到這里,本文接近尾聲了,我也感覺意猶未盡,但是再寫下去怕是成飛流直下三千尺了,我想用一句話回答這個(gè)問題:
小而美是每一個(gè)工程師最終會(huì)選擇自我修養(yǎng),Koa2 是小而美的,能與它結(jié)合的必然也是小而美的,那么在 2018 年,就非 Parcel 莫屬,小而美絕配,關(guān)于 Parcel 如何 AntDesign/React/Bootstrap 等這些前端框架庫組合使用,可以關(guān)注?Koa2解讀+數(shù)據(jù)抓取+實(shí)戰(zhàn)電影網(wǎng)站?了解更多姿勢。
回到本文的標(biāo)題:Koa2 還有多久取代 Express?我想完全替代是不可能的,但是新項(xiàng)目使用 Koa2(以及基于它封裝的框架)將會(huì)在數(shù)量上碾壓 Express,時(shí)間呢,2018 - 2019 兩年足矣,那么 2018 年起,但求不落后,加油!
轉(zhuǎn)自https://segmentfault.com/a/1190000013025296?utm_source=sf-related
總結(jié)
以上是生活随笔為你收集整理的Koa2 还有多久取代 Express的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: linux分页显示文件内容命令,Linu
- 下一篇: 思科静态路由配置简单命令