nodejs框架对比:koa和express

目前比较流行的nodejs框架有expresskoaegg.js,还有就是和ts相关的框架nest.js

无论是哪种框架,其核心都是基于中间件来实现的,而中间件执行的方式都跟洋葱模型有关,它们的差别主要也是在洋葱模型的执行方式上。

什么是洋葱模型?

洋葱模型,就像洋葱一样,一层包裹一层,而nodejs框架的执行就像是中间穿过洋葱的一条线,而每一层洋葱皮就代表一个中间件,进入时穿过多少层,出来时还得穿出多少层,具有先进后出(栈)的特点。

借鉴张图:洋葱模型

穿进来时:middleware1 -> middleware2 -> middleware3 -> center
穿出来时:center -> middleware3 -> middleware2 -> middleware1

  • 穿进来时,中间件的切换主要靠next()关键字来实现的
  • 穿出来时,则是按中间件执行完毕后,按照原路径反回去

Express

ExpressNode.js 初期就是一个热度较高、成熟的 Web 框架,并且包括的应用场景非常齐全。同时基于 Express,也诞生了一些场景型的框架,常见的就如上面我们提到的 Nest.js框架

KOA

随着nodejs发展,出现了以await/async为核心的语法糖,Express原班人马为了实现一个高可用、高性能、更健壮,并且符合当前Node.js 版本的框架,开发出了可定制KOA框架。
Egg.js 就是在 KOA 基础上,做了各种比较成熟的中间件和模块,可以说是在 KOA框架基础上的最佳实践,用以满足开发者开箱即用的特性。

所以在对比差异时,我们主要对比ExpressKOA就可以看出它们间的主要区别

Express和KOA的差异

  • Express 封装、内置了很多中间件,比如 connectrouter,而 KOA 则比较轻量,开发者可以根据自身需求定制框架;
  • Express 是基于 callback 来处理中间件的,而 KOA 则是基于 await/async
  • 在异步执行中间件时,Express非严格按照洋葱模型执行中间件,而 KOA 则是严格遵循的。
  • Express 使用 callback捕获异常,对于深层次的异常捕获不了,Koa 使用 try catch,能更好地解决异常捕获。

下面来以例子说明一下两个框架的执行过程不一样的地方:

Express示例

  1. 写个express服务器
  • app.use:用于中间件和路由的处理。当参数是函数时,匹配所有路由;当参数是字符串时,匹配具体对应的路由
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. 启动服务
    node ./src/express-test.js
  2. 在浏览器访问http://localhost:3000/,结果如下:
    express服务器
  3. 关闭和管理服务
    关闭服务的操作:在当前目录下ctrl+c结束进程

KOA示例

KOA的用法其实和Express差不多,只不过Express内置了router,而KOA需要自己定制:

  1. 安装:npm i koa koa-router chalk
  2. 中间件的方法和Express基本一样,只不过将req, res参数换成了上下文ctx
  3. 设置路由需要用路由实例方法 router.get 方式,且要把路由实例设置到koa实例上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服务器

可以看到如果是中间件中的代码是同步的时候,两者的的执行顺序是一样的。现在修改一下:

  1. 增加一个执行异步操作的中间件
  2. 每一个中间件,都增加上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');
});

此时,再观察两者的输出顺序:

Express是顺序不是严格按照洋葱模型的:

Express

KOA的顺序是严格按照洋葱模型的:

koa

发生这样的原因是两者基于的nodejs的版本不一样导致的。

参考:
https://blog.csdn.net/xgangzai/article/details/109108387
https://www.jianshu.com/p/6f7930687835/

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,110评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,443评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,474评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,881评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,902评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,698评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,418评论 3 419
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,332评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,796评论 1 316
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,968评论 3 337
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,110评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,792评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,455评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,003评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,130评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,348评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,047评论 2 355

推荐阅读更多精彩内容