node.js中koa和express的差異對(duì)比
前言
最近利用業(yè)余的時(shí)間,跟著 coderwhy 老師學(xué)習(xí) node.js,了解以及掌握一些服務(wù)端的常見知識(shí):
fileSystem:文件讀取模塊。events:事件流Buffer:node 中處理二進(jìn)制的方式http 創(chuàng)建服務(wù)器Stream流的讀寫操作…
確實(shí)學(xué)習(xí)到了很多東西,填充了自己的知識(shí)體系的未知領(lǐng)域。
node.js 也許是前端開發(fā)者踏入服務(wù)端開發(fā)的最好選擇。同樣的 JavaScript,同樣的語法,以及同樣的你,基本上可以達(dá)到無縫銜接的開發(fā)。
對(duì)于 node.js 而言,社區(qū)里面出現(xiàn)了非常多的框架,快速上手,敏捷開發(fā)。
koa
和 express
就是其中的比較兩個(gè)突出的框架。
在閱讀下文之前,希望你掌握了 express 和 koa 的基本使用,不然下面內(nèi)容對(duì)你的幫助也許不是那么的大。
koa 和 express 的介紹
express 是一個(gè)基于 node.js 平臺(tái),快速,開放,極簡的 web 開發(fā)框架。express 官網(wǎng)
koa 是基于 node.js 平臺(tái)的下一代 web 開發(fā)框架。koa 官網(wǎng)
兩個(gè)框架都是同一個(gè)團(tuán)隊(duì)開發(fā)的,都是 node.js 中比較優(yōu)秀的框架。
都是 node.js 框架,同一個(gè)團(tuán)隊(duì)為什么要開發(fā)兩個(gè)呢?
express 也許是 node.js 最早出的框架,里面集成了大量的中間件,造成了框架的笨重性。團(tuán)隊(duì)領(lǐng)隊(duì)人 TJ 發(fā)現(xiàn)了 express 的設(shè)計(jì)是有缺陷的,如果想要修復(fù)這個(gè)設(shè)計(jì)缺陷,就會(huì)造成 express 的框架重構(gòu)。
基于上面的種種原因(當(dāng)然還有不知道的),就打算重新寫一個(gè)新的框架->koa,來實(shí)現(xiàn) express 的不足之處。
express 現(xiàn)在有團(tuán)隊(duì)中的團(tuán)員維護(hù),基本上也很少更新了。
koa 由團(tuán)隊(duì)領(lǐng)隊(duì)人 TJ 主要維護(hù)。
? --來自 coderwhy 老師的閑談
上面的閑談的內(nèi)容不重要,當(dāng)個(gè)樂子開心一下就好了。
一起看看 express 和 koa 在 github 上的星標(biāo):
可以發(fā)現(xiàn) express 的使用率還是比 koa 高,盡管 express 笨重,設(shè)計(jì)有缺陷,但是對(duì)于開發(fā)者而言,當(dāng)不考慮這些因素情況下,express 還是吃香的。
兩者都是同一團(tuán)隊(duì)寫的兩個(gè)框架,那么核心的思想肯定是相同的,當(dāng)然肯定會(huì)也存在差異,那么接下來就來重點(diǎn)比較一下其中的差異吧。
koa 和 express 的差異對(duì)比
下面主要從兩個(gè)方面來分析其中的差異:設(shè)計(jì)架構(gòu)、中間件。
因?yàn)橐彩堑谝淮谓佑| koa (express 以前是接觸了的),如果存在有誤的地方,請(qǐng)指出來,虛心受教,共同進(jìn)步。
koa 和 express 的設(shè)計(jì)架構(gòu)對(duì)比
express 是完整和強(qiáng)大的,里面集成了大量的中間件,比如說:路由,靜態(tài)資源等中間件。對(duì)于開發(fā)者而言,技術(shù)統(tǒng)一,都是使用 express 內(nèi)部提供的。
koa 是靈活和自由的,基本上沒有集成任何中間件(核心代碼只有大致1600行左右),中間件都需要自己去安裝。對(duì)于開發(fā)者而言,選擇技術(shù)的類型是多樣的,豐富的。
webstorm 和 vscode 的使用,都是因人而異,沒有誰強(qiáng)誰弱。那么對(duì)于 express 和 koa 也是同樣的道理,各自有各自優(yōu)勢。
接下來我們一起來聽聽 express 和 koa 獨(dú)白:
express:hi,koa,我倆同處一體,我倆比比?
koa:???
express:我倆的發(fā)動(dòng)機(jī)都是中間件
,我有三個(gè)兄弟:request
,response
,next
,你有幾個(gè)兄弟呢?
koa:額,我有兩個(gè)兄弟:context
,next
。不過我這 context
兄弟很厲害,以一敵二(request,response)。
express:我自帶路由(Router
),直接使用即可,你呢?
koa:安裝。(koa-router
或者 @dva/router
)
express:我可以自己暴露靜態(tài)資源,你呢?
koa:安裝。(koa-static
)
express:我只需要配置一下,就可以解析客戶端傳遞 application/json 的格式數(shù)據(jù),你呢?
koa:還是安裝。(koa-bodyparser
)
express:你能不能不要安裝呀,你就沒有自帶的?我還是只需要配置一下,就可以解析客戶端傳遞 x-www-form-urlencoded 的格式數(shù)據(jù),你呢?
koa:哈哈哈,不好意思,我不用配置,我也能解析 x-www-form-urlencoded 的格式數(shù)據(jù)。
koa:我還能安裝 @koa/multer
來實(shí)現(xiàn)文件上傳,你自帶了嗎?
express:額。。。我這個(gè)還真沒自帶,我也需要安裝 multer
來實(shí)現(xiàn)。
koa:讓你裝 xxx。你我本是同根生,相煎何太急,和平相處不行嘛。
express:。。。
TJ:莫吵了,把你倆創(chuàng)建出來,設(shè)計(jì)理念本就是不相同的。express 你走的完整路線,koa 走的是靈活路線,所以不用相互較勁,和氣生財(cái)。
koa 和 express 的中間件對(duì)比
express 和 koa 的核心,都是中間件。
簡單的來說,理解了中間件,也就理解了express 和 koa。
何為中間件?
那么何為中間件呢?
express 和 koa 都能創(chuàng)建一個(gè)服務(wù)器實(shí)例 app,那么給 app 傳入一個(gè)回調(diào)函數(shù),那么該回調(diào)函數(shù)就被稱為中間件(middleware)。
express 創(chuàng)建中間件:
// 方式一:use(fn) app.use((req, res, next) => {}) // 方式二:use(path, fn) app.use('/', (req, res, next) => {}) // 方式三:method(path, fn) app.get('/', (req, res, next) => {}) // 方式四:method(path, fn1, fn2, fn3) app.get('/', (req, res, next) => {}, (req, res, next) => {})
koa 創(chuàng)建中間件:
// 方式一:use(fn) app.use((ctx, next) => {}) // 方式二:use(path, fn) app.use('/', (ctx, next) => {})
在這里就不展開怎么使用中間件了,我相信你會(huì)的,express 和 koa 的中間件道理是相同的。
中間件的執(zhí)行順序(同步,異步)
express 同步
app.use((req, res, next) => { console.log("中間件01: next前"); next(); console.log("中間件01: next后"); }); app.use((req, res, next) => { console.log("中間件02: next前"); next(); console.log("中間件02: next后"); }); app.use((req, res, next) => { console.log("中間件03") });
express 異步
function mockAsync () { return new Promise((resolve) => { setTimeout(() => { resolve(321) }, 1000) }) } app.use((req, res, next) => { console.log("中間件01: next前"); next(); console.log("中間件01: next后"); }); app.use((req, res, next) => { console.log("中間件02: next前"); next(); console.log("中間件02: next后"); }); app.use(async (req, res, next) => { const data = await mockAsync() console.log("中間件03: next前"); });
koa 同步
app.use((ctx, next) => { console.log('中間件01: next前'); next() console.log('中間件01: next后'); }) app.use((ctx, next) => { console.log("中間件02: next前"); next(); console.log("中間件02: next后"); }); app.use((ctx, next) => { console.log("中間件03"); });
koa 異步
function mockAsync() { return new Promise((resolve) => { setTimeout(() => { resolve(321); }, 1000); }); } app.use((ctx, next) => { console.log('中間件01: next前'); next() console.log('中間件01: next后'); }) app.use((ctx, next) => { console.log("中間件02: next前"); next(); console.log("中間件02: next后"); }); app.use(async (ctx, next) => { const res = await mockAsync() console.log("中間件03"); });
上面四個(gè)案例,分別從:
- express 同步
- express 異步
- koa 同步
- koa 異步
來分析了中間的執(zhí)行順序,可以得出兩點(diǎn)結(jié)論:
- 無論是 express 還是 koa,當(dāng)中間件是同步代碼并且調(diào)用了 next 函數(shù),那么程序運(yùn)行就會(huì)先執(zhí)行每個(gè)中間件next函數(shù)之前的代碼,當(dāng)執(zhí)行到最后一個(gè)中間件時(shí),又會(huì)回滾執(zhí)行每個(gè)中間件next 函數(shù)后的代碼(類似于 數(shù)據(jù)結(jié)構(gòu)中的 first in last out)。
- 無論是 express 還是 koa,當(dāng)遇到中間件中存在異步代碼,就會(huì)停止向下執(zhí)行,而是回到上一個(gè)中間件繼續(xù)執(zhí)行。
所以對(duì)于 express 和 koa 在中間件執(zhí)行上,**表現(xiàn)形式**上是相同的。
而不相同之處就是在于 express 和 koa 在針對(duì)中間件存在異步代碼時(shí),**處理方式**不同(簡單的來說也就是內(nèi)部的 next 函數(shù)實(shí)現(xiàn)不同)。
koa 和 express 不同的異步處理方式
假如存在這樣的一個(gè)案例:存在兩個(gè)中間件,一個(gè)是業(yè)務(wù)接口處理的中間件,一個(gè)是針對(duì)處理相同數(shù)據(jù)的中間件(比如:針對(duì)每個(gè)接口返回用戶信息),這里的獲取用戶信息,就是異步操作。
那么針對(duì) express 會(huì)寫出以下代碼:
function getUserInfo () { return new Promise((resolve) => { setTimeout(() => { resolve({name: 'copyer', sex: 'man'}) }, 1000) }) } app.get('/list', (req, res, next) => { const list = [ { id: "1", content: "列表1" }, { id: "2", content: "列表2" }, ]; next(); res.json({ list, userInfo: req?.userInfo // 返回用戶信息,需要通過下個(gè)中間件來獲取 }) }); app.use(async (req, res, next) => { // mock 異步代碼,拿到用戶信息 const data = await getUserInfo(); console.log(data); // { name: 'copyer', sex: 'man' } req.userInfo = data; // 設(shè)置用戶信息 });
當(dāng)我們?cè)L問 list 接口時(shí),發(fā)現(xiàn)是拿不到用戶信息(userInfo),因?yàn)橛龅绞钱惒胶瘮?shù),就會(huì)停止繼續(xù)執(zhí)行下面的代碼,而是回到上一個(gè)中間件繼續(xù)執(zhí)行,所以沒有拿到用戶信息。
koa 也是同樣的道理,但是 koa 卻是可以解決這個(gè)問題。代碼如下:
function getUserInfo() { return new Promise((resolve) => { setTimeout(() => { resolve({ name: "copyer", sex: "man" }); }, 1000); }); } router.get('/list', async (ctx, next) => { const list = [ { id: "1", content: "列表1" }, { id: "2", content: "列表2" }, ]; await next(); /*****************重點(diǎn)代碼*********************/ ctx.body = { list, ctx: ctx?.userInfo } }); router.use(async (ctx, next) => { const res = await getUserInfo(); console.log(res); // { name: 'copyer', sex: 'man' } ctx.userInfo = res; // 設(shè)置用戶信息 }); app.use(router.routes())
看上面標(biāo)記的重點(diǎn)代碼,那么就是處理異步的關(guān)鍵。在 next
執(zhí)行前面,加上一個(gè) await
,這樣就能正常的拿到用戶信息。
await next()
的意思就是等待下個(gè)中間件執(zhí)行完成,那么這樣用戶信息也就設(shè)置成功了。
那么肯定有人這樣想,那么我在 express 調(diào)用 next 函數(shù)時(shí),也加上 await ,是不是也解決了?想法很美好,但是行不通的。為撒?
express 中的 next 函數(shù),返回值一個(gè)void,沒有返回值。
這里的 next 函數(shù)接受一個(gè)參數(shù) err,也就是錯(cuò)誤信息,針對(duì)全局異常處理的收集時(shí),就會(huì)使用。
koa 中的 next 函數(shù),返回值一個(gè)Promise。
這里的 next 函數(shù)不接受參數(shù),所以全局錯(cuò)誤的異常處理,需要另想它法。
koa 和 express 在異步處理函數(shù),最大的差別就是 next 函數(shù)實(shí)現(xiàn)不同,那么也就造成了中間件在異步上的使用不同。
koa 在上一個(gè)中間件拿取下一個(gè)異步中間件的數(shù)據(jù),然后返回。express 卻是不行,這是 express 設(shè)計(jì)上的缺陷。
洋蔥模型
想想平時(shí)生活中的洋蔥,是不是一層一層的。
中間件從上往下(從外往里),然后從下往上(從里往外)執(zhí)行,無論是同步還是異步都滿足,koa 是符合洋蔥模型的。
express 是在同步的時(shí)候是滿足洋蔥模型的,但是異步的時(shí)候卻是不能滿足洋蔥模型。
總結(jié)
這篇主要從設(shè)計(jì)架構(gòu)和中間件兩個(gè)方面來解釋說明 express 和 koa 之間的差異。
比較差異并不是為了證明誰好誰弱,而是為了另一方面來充分認(rèn)識(shí)框架隱藏的知識(shí)點(diǎn),加深自己理解。
到此這篇關(guān)于node.js中koa和express的差異對(duì)比的文章就介紹到這了,更多相關(guān)koa和express對(duì)比內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Node.js中Express框架使用axios同步請(qǐng)求(async+await)實(shí)現(xiàn)方法
- node.js使用express-jwt報(bào)錯(cuò):expressJWT?is?not?a?function解決
- Node.js使用express寫接口的具體代碼
- Node.js?express中的身份認(rèn)證的實(shí)現(xiàn)
- 使用Express+Node.js對(duì)mysql進(jìn)行增改查操作?
- node.js三個(gè)步驟實(shí)現(xiàn)一個(gè)服務(wù)器及Express包使用
- Node.js中Express框架的使用教程詳解
- node.js+express留言板功能實(shí)現(xiàn)示例
- node.js使用express-fileupload中間件實(shí)現(xiàn)文件上傳
- Node.js+express+socket實(shí)現(xiàn)在線實(shí)時(shí)多人聊天室
- Express框架實(shí)現(xiàn)簡單攔截器功能示例
相關(guān)文章
node.js中的querystring.parse方法使用說明
這篇文章主要介紹了node.js中的querystring.parse方法使用說明,本文介紹了querystring.parse的方法說明、語法、接收參數(shù)、使用實(shí)例和實(shí)現(xiàn)源碼,需要的朋友可以參考下2014-12-12Windows下快速搭建NodeJS本地服務(wù)器的步驟
本篇文章主要介紹了Windows下快速搭建NodeJS本地服務(wù)器的步驟,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。2017-08-08nodejs不用electron實(shí)現(xiàn)打開文件資源管理器并選擇文件
最近在開發(fā)一些小腳本,用 nodejs 實(shí)現(xiàn),其中很多功能需要選擇一個(gè)/多個(gè)文件,或者是選擇一個(gè)文件夾,這種情況下網(wǎng)上給出的解決方案都是 electron,但是我一個(gè)小腳本用 electron 屬實(shí)有點(diǎn)夸張了,后來轉(zhuǎn)念一想可以通過 powershell 來實(shí)現(xiàn)類似的功能,需要的朋友可以參考下2024-01-01node-red教程之dashboard簡介與輸入型儀表板控件的使用
Node-red支持自定義節(jié)點(diǎn),當(dāng)然也就支持自定義圖形化的節(jié)點(diǎn)。也有優(yōu)秀的開發(fā)者把自己建立的圖形化節(jié)點(diǎn)無償分享。這里給出一個(gè)股票界面的例子,讓大家看一看優(yōu)秀的node-red界面能做到什么樣子2022-01-01nodejs與瀏覽器中全局對(duì)象區(qū)別點(diǎn)總結(jié)
在本篇文章里小編給大家整理的是一篇關(guān)于nodejs與瀏覽器中全局對(duì)象區(qū)別點(diǎn)總結(jié)內(nèi)容,對(duì)此有需要的朋友們可以學(xué)習(xí)下。2021-12-12