nodejs框架對(duì)比:koa和express

目前比較流行的nodejs框架有express、koaegg.js,還有就是和ts相關(guān)的框架nest.js。

無(wú)論是哪種框架,其核心都是基于中間件來(lái)實(shí)現(xiàn)的,而中間件執(zhí)行的方式都跟洋蔥模型有關(guān),它們的差別主要也是在洋蔥模型的執(zhí)行方式上。

什么是洋蔥模型?

洋蔥模型,就像洋蔥一樣,一層包裹一層,而nodejs框架的執(zhí)行就像是中間穿過(guò)洋蔥的一條線(xiàn),而每一層洋蔥皮就代表一個(gè)中間件,進(jìn)入時(shí)穿過(guò)多少層,出來(lái)時(shí)還得穿出多少層,具有先進(jìn)后出(棧)的特點(diǎn)。

借鑒張圖:洋蔥模型

穿進(jìn)來(lái)時(shí):middleware1 -> middleware2 -> middleware3 -> center
穿出來(lái)時(shí):center -> middleware3 -> middleware2 -> middleware1

  • 穿進(jìn)來(lái)時(shí),中間件的切換主要靠next()關(guān)鍵字來(lái)實(shí)現(xiàn)的
  • 穿出來(lái)時(shí),則是按中間件執(zhí)行完畢后,按照原路徑反回去

Express

ExpressNode.js 初期就是一個(gè)熱度較高、成熟的 Web 框架,并且包括的應(yīng)用場(chǎng)景非常齊全。同時(shí)基于 Express,也誕生了一些場(chǎng)景型的框架,常見(jiàn)的就如上面我們提到的 Nest.js框架

KOA

隨著nodejs發(fā)展,出現(xiàn)了以await/async為核心的語(yǔ)法糖,Express原班人馬為了實(shí)現(xiàn)一個(gè)高可用、高性能、更健壯,并且符合當(dāng)前Node.js 版本的框架,開(kāi)發(fā)出了可定制KOA框架。
Egg.js 就是在 KOA 基礎(chǔ)上,做了各種比較成熟的中間件和模塊,可以說(shuō)是在 KOA框架基礎(chǔ)上的最佳實(shí)踐,用以滿(mǎn)足開(kāi)發(fā)者開(kāi)箱即用的特性。

所以在對(duì)比差異時(shí),我們主要對(duì)比ExpressKOA就可以看出它們間的主要區(qū)別

Express和KOA的差異

  • Express 封裝、內(nèi)置了很多中間件,比如 connectrouter,而 KOA 則比較輕量,開(kāi)發(fā)者可以根據(jù)自身需求定制框架;
  • Express 是基于 callback 來(lái)處理中間件的,而 KOA 則是基于 await/async
  • 在異步執(zhí)行中間件時(shí),Express非嚴(yán)格按照洋蔥模型執(zhí)行中間件,而 KOA 則是嚴(yán)格遵循的。
  • Express 使用 callback捕獲異常,對(duì)于深層次的異常捕獲不了,Koa 使用 try catch,能更好地解決異常捕獲。

下面來(lái)以例子說(shuō)明一下兩個(gè)框架的執(zhí)行過(guò)程不一樣的地方:

Express示例

  1. 寫(xiě)個(gè)express服務(wù)器
  • app.use:用于中間件和路由的處理。當(dāng)參數(shù)是函數(shù)時(shí),匹配所有路由;當(dāng)參數(shù)是字符串時(shí),匹配具體對(duì)應(yīng)的路由
mkdir node-demo
cd node-demo
npm init -y
mkdir src
touch express.js
const express = require('express')
const app = express()
const port = 3000

const server = app.listen(port, () => {
  const host = server.address().address
  const port = server.address().port
  console.log(`Express server is listening on ${host}:${port}!`)
})

app.use((req, res, next) => {
  console.log('middleware1 start')
  next(); // 跳到下一層洋蔥中間件
  console.log('middleware1 end')
})

app.use((req, res, next) => {
  console.log('middleware2 start')
  next(); // 跳到下一層洋蔥中間件
  console.log('middleware2 end')
})

app.use((req, res, next) => {
  console.log('middleware3 start')
  next(); // 跳到下一層洋蔥中間件
  console.log('middleware3 end')
})

app.get('/', (req, res) => {
  res.send('hello express')
})

  1. 啟動(dòng)服務(wù)
    node ./src/express-test.js
  2. 在瀏覽器訪(fǎng)問(wèn)http://localhost:3000/,結(jié)果如下:
    express服務(wù)器
  3. 關(guān)閉和管理服務(wù)
    關(guān)閉服務(wù)的操作:在當(dāng)前目錄下ctrl+c結(jié)束進(jìn)程

KOA示例

KOA的用法其實(shí)和Express差不多,只不過(guò)Express內(nèi)置了router,而KOA需要自己定制:

  1. 安裝:npm i koa koa-router chalk
  2. 中間件的方法和Express基本一樣,只不過(guò)將req, res參數(shù)換成了上下文ctx
  3. 設(shè)置路由需要用路由實(shí)例方法 router.get 方式,且要把路由實(shí)例設(shè)置到koa實(shí)例上app.use(router.routes())
const chalk = require('chalk')
const Koa = require('koa')
const Router = require('koa-router')
const app = new Koa()
const router = new Router()
const port = 9000

// 使用ctx上下文
app.use((ctx, next) => {
  console.log('middleware1 start')
  next(); // 跳到下一層洋蔥中間件
  console.log('middleware1 end')
})

app.use((ctx, next) => {
  console.log('middleware2 start')
  next(); // 跳到下一層洋蔥中間件
  console.log('middleware2 end')
})

app.use((ctx, next) => {
  console.log('middleware3 start')
  next(); // 跳到下一層洋蔥中間件
  console.log('middleware3 end')
})
router.get('/', (ctx) => {
  ctx.body = 'Hello koa!'
})


// 使用router
app.use(router.routes())
app.listen(port, 'localhost', () => {
  console.log(chalk.yellow(`Express server is listening on ${port}!`))
})
koa服務(wù)器

可以看到如果是中間件中的代碼是同步的時(shí)候,兩者的的執(zhí)行順序是一樣的?,F(xiàn)在修改一下:

  1. 增加一個(gè)執(zhí)行異步操作的中間件
  2. 每一個(gè)中間件,都增加上async await處理
// 這里只舉一例子,其它的中間件是一樣的
app.use(async (req, res, next) => {
  console.log('middleware1 start')
  await next(); // 跳到下一層洋蔥中間件
  console.log('middleware1 end')
})
app.use(async (req, res, next) => {
  console.log('async start');
  await next();
  await new Promise(
      (resolve) => 
          setTimeout(
              () => {
                  console.log(`wait 1000 ms end`);
                  resolve()
              }, 
          1000
      )
  );
  console.log('async end');
});

此時(shí),再觀察兩者的輸出順序:

Express是順序不是嚴(yán)格按照洋蔥模型的:

Express

KOA的順序是嚴(yán)格按照洋蔥模型的:

koa

發(fā)生這樣的原因是兩者基于的nodejs的版本不一樣導(dǎo)致的。

參考:
https://blog.csdn.net/xgangzai/article/details/109108387
http://www.itdecent.cn/p/6f7930687835/

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容