koa 和 express 的对比

news2024/12/26 1:01:36

前言

天冷了,唯有学习来温暖自己。

最近利用业余的时间,跟着 coderwhy 老师学习 node.js,了解以及掌握一些服务端的常见知识:

  • fileSystem:文件读取模块。
  • events:事件流
  • Buffer:node 中处理二进制的方式
  • http 创建服务器
  • Stream流的读写操作

确实学习到了很多东西,填充了自己的知识体系的未知领域。

node.js 也许是前端开发者踏入服务端开发的最好选择。同样的 JavaScript,同样的语法,以及同样的你,基本上可以达到无缝衔接的开发。

对于 node.js 而言,社区里面出现了非常多的框架,快速上手,敏捷开发。

koaexpress 就是其中的比较两个突出的框架。

在阅读下文之前,希望你掌握了 express 和 koa 的基本使用,不然下面内容对你的帮助也许不是那么的大。

koa 和 express 的介绍

express 是一个基于 node.js 平台,快速,开放,极简的 web 开发框架。express 官网

koa 是基于 node.js 平台的下一代 web 开发框架。koa 官网

两个框架都是同一个团队开发的,都是 node.js 中比较优秀的框架。

都是 node.js 框架,同一个团队为什么要开发两个呢?

express 也许是 node.js 最早出的框架,里面集成了大量的中间件,造成了框架的笨重性。团队领队人 TJ 发现了 express 的设计是有缺陷的,如果想要修复这个设计缺陷,就会造成 express 的框架重构。

基于上面的种种原因(当然还有不知道的),就打算重新写一个新的框架->koa,来实现 express 的不足之处。

express 现在有团队中的团员维护,基本上也很少更新了。

koa 由团队领队人 TJ 主要维护。

​ --来自 coderwhy 老师的闲谈

上面的闲谈的内容不重要,当个乐子开心一下就好了。

一起看看 express 和 koa 在 github 上的星标:
在这里插入图片描述
可以发现 express 的使用率还是比 koa 高,尽管 express 笨重,设计有缺陷,但是对于开发者而言,当不考虑这些因素情况下,express 还是吃香的。

两者都是同一团队写的两个框架,那么核心的思想肯定是相同的,当然肯定会也存在差异,那么接下来就来重点比较一下其中的差异吧。

koa 和 express 的差异对比

下面主要从两个方面来分析其中的差异:设计架构中间件

因为也是第一次接触 koa (express 以前是接触了的),如果存在有误的地方,请指出来,虚心受教,共同进步。

koa 和 express 的设计架构对比

express 是完整和强大的,里面集成了大量的中间件,比如说:路由,静态资源等中间件。对于开发者而言,技术统一,都是使用 express 内部提供的。
在这里插入图片描述
koa 是灵活和自由的,基本上没有集成任何中间件(核心代码只有大致1600行左右),中间件都需要自己去安装。对于开发者而言,选择技术的类型是多样的,丰富的。
在这里插入图片描述

webstorm 和 vscode 的使用,都是因人而异,没有谁强谁弱。那么对于 express 和 koa 也是同样的道理,各自有各自优势。

接下来我们一起来听听 express 和 koa 独白:

express:hi,koa,我俩同处一体,我俩比比?

koa:???

express:我俩的发动机都是中间件,我有三个兄弟:requestresponsenext,你有几个兄弟呢?

koa:额,我有两个兄弟:contextnext。不过我这 context 兄弟很厉害,以一敌二(request,response)。

express:我自带路由(Router),直接使用即可,你呢?

koa:安装。(koa-router 或者 @dva/router

express:我可以自己暴露静态资源,你呢?

koa:安装。(koa-static

express:我只需要配置一下,就可以解析客户端传递 application/json 的格式数据,你呢?

koa:还是安装。(koa-bodyparser

express:你能不能不要安装呀,你就没有自带的?我还是只需要配置一下,就可以解析客户端传递 x-www-form-urlencoded 的格式数据,你呢?

koa:哈哈哈,不好意思,我不用配置,我也能解析 x-www-form-urlencoded 的格式数据。

koa:我还能安装 @koa/multer 来实现文件上传,你自带了吗?

express:额。。。我这个还真没自带,我也需要安装 multer 来实现。

koa:让你装 xxx。你我本是同根生,相煎何太急,和平相处不行嘛。

express:。。。

TJ:莫吵了,把你俩创建出来,设计理念本就是不相同的。express 你走的完整路线,koa 走的是灵活路线,所以不用相互较劲,和气生财。

koa 和 express 的中间件对比

express 和 koa 的核心,都是中间件。

简单的来说,理解了中间件,也就理解了express 和 koa。

何为中间件?

那么何为中间件呢?

express 和 koa 都能创建一个服务器实例 app,那么给 app 传入一个回调函数,那么该回调函数就被称为中间件(middleware)

express 创建中间件:

// 方式一: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 创建中间件:

// 方式一:use(fn)
app.use((ctx, next) => {})
// 方式二:use(path, fn)
app.use('/', (ctx, next) => {})

在这里就不展开怎么使用中间件了,我相信你会的,express 和 koa 的中间件道理是相同的。

中间件的执行顺序(同步,异步)

  • 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");
});

在这里插入图片描述

上面四个案例,分别从:

  • express 同步
  • express 异步
  • koa 同步
  • koa 异步

来分析了中间的执行顺序,可以得出两点结论:

  1. 无论是 express 还是 koa,当中间件是同步代码并且调用了 next 函数,那么程序运行就会先执行每个中间件next函数之前的代码,当执行到最后一个中间件时,又会回滚执行每个中间件next 函数后的代码(类似于 数据结构中的 first in last out)。
  2. 无论是 express 还是 koa,当遇到中间件中存在异步代码,就会停止向下执行,而是回到上一个中间件继续执行。

所以对于 express 和 koa 在中间件执行上,**表现形式**上是相同的。

而不相同之处就是在于 express 和 koa 在针对中间件存在异步代码时,**处理方式**不同(简单的来说也就是内部的 next 函数实现不同)。

koa 和 express 不同的异步处理方式

假如存在这样的一个案例:存在两个中间件,一个是业务接口处理的中间件,一个是针对处理相同数据的中间件(比如:针对每个接口返回用户信息),这里的获取用户信息,就是异步操作。

那么针对 express 会写出以下代码:

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 // 返回用户信息,需要通过下个中间件来获取
  })
});

app.use(async (req, res, next) => {
  // mock 异步代码,拿到用户信息
  const data = await getUserInfo();
  console.log(data); // { name: 'copyer', sex: 'man' }
  req.userInfo = data; // 设置用户信息
});

当我们访问 list 接口时,发现是拿不到用户信息(userInfo),因为遇到是异步函数,就会停止继续执行下面的代码,而是回到上一个中间件继续执行,所以没有拿到用户信息。

koa 也是同样的道理,但是 koa 却是可以解决这个问题。代码如下:

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(); /*****************重点代码*********************/
  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; // 设置用户信息
});

app.use(router.routes())

看上面标记的重点代码,那么就是处理异步的关键。在 next 执行前面,加上一个 await,这样就能正常的拿到用户信息。

await next() 的意思就是等待下个中间件执行完成,那么这样用户信息也就设置成功了。

那么肯定有人这样想,那么我在 express 调用 next 函数时,也加上 await ,是不是也解决了?想法很美好,但是行不通的。为撒?

express 中的 next 函数,返回值一个void,没有返回值。

这里的 next 函数接受一个参数 err,也就是错误信息,针对全局异常处理的收集时,就会使用。

在这里插入图片描述

koa 中的 next 函数,返回值一个Promise。

这里的 next 函数不接受参数,所以全局错误的异常处理,需要另想它法。

在这里插入图片描述

koa 和 express 在异步处理函数,最大的差别就是 next 函数实现不同,那么也就造成了中间件在异步上的使用不同。

koa 在上一个中间件拿取下一个异步中间件的数据,然后返回。express 却是不行,这是 express 设计上的缺陷。

洋葱模型

想想平时生活中的洋葱,是不是一层一层的。

在这里插入图片描述

中间件从上往下(从外往里),然后从下往上(从里往外)执行,无论是同步还是异步都满足,koa 是符合洋葱模型的。

express 是在同步的时候是满足洋葱模型的,但是异步的时候却是不能满足洋葱模型。

总结

这篇主要从设计架构中间件两个方面来解释说明 express 和 koa 之间的差异。

比较差异并不是为了证明谁好谁弱,而是为了另一方面来充分认识框架隐藏的知识点,加深自己理解。

若你觉得有误,请指出;若对你有用,请点个赞。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/61267.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

高仿英雄联盟游戏网页制作作业 英雄联盟LOL游戏HTML网页设计模板 简单学生网页设计 静态HTML CSS网站制作成品

🎉精彩专栏推荐👇🏻👇🏻👇🏻 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 💂 作者主页: 【主页——🚀获取更多优质源码】 🎓 web前端期末大作业…

Java—代理

文章目录先举一个例子:开闭原则什么是代理两种调用的方式:代理定义:代理的实现方式静态代理代理的目的:如何让程序知道要增强的功能是谁?静态代理缺点:动态代理什么是动态代理动态代理的实现静态代理和动态…

26. SAP ABAP OData Gateway 框架里 /IWFND, /IWBEP 这些缩写代表了什么含义?

文章目录 GWFNDBEP本文参考链接本教程前一篇文章 - 25. 答疑 - SAP OData 框架处理 Metadata 元数据请求的实现细节,前后端组件部署在同一台物理服务器,我们深入了 SAP ABAP OData 框架来学习其元数据请求的执行明细。 我们在文章里看到了不少以 /IWFND/, /IWBEP 这些命名空…

MAUI Blazor (Windows) App 动态设置窗口标题

原文链接 https://www.cnblogs.com/densen2014/p/16950996.html 接着上一篇"如何为面向 Windows 的 MAUI Blazor 应用程序设置窗口标题?" Tips: 总所周知,MAUI 除了 Windows App 其他平台窗口是没有 Title 这回事的. 在 Blazor 里面可以直接给页面打上…

时间轴-新年倒计时(实操java)

文章目录一、前言二、前端代码实现1、效果图年月日倒计时秒杀1天倒计时秒杀60秒倒计时2、代码实操(微信小程序前端)①在utils文件夹下新建js文件:getperiod.js工具类②引入js,在页面index.js开头引入③完整代码3、倒计时实现①1天…

学习python第一天(数据类型)

关于Python的数据类型 Python数据类型包括: 数字类型,字符类型,布尔类型,空类型,列表类型,元组类型,字典类型 1、数字类型 包括:整型int 浮点型float(有小数位的都是是浮点型) 注…

自己写Spring组件-01手写Bean注册器

简介 在进行web开发的时候,我们经常使用Component、Services、Controller等注解去声明Bean,然后Spring就会帮我们注册。 如果我们想要自己写一个组件(方便后期使用),进行无感引入的时候,就需要自己去注册B…

【计算机网络】计算机网络复习总结 ----- 链路层

计算机网络 内容管理数据链路层 Data Link Layer相关概念术语link 链路data link 数据链路帧 frameMTU maximum transfer Unit 最大传送单元PPP point to point Protcol 点对点协议MAC 地址 media access control网桥 bridge交换机 switch成帧 规则成帧定界字符计数法字符填充分…

QT:文件介绍

UI:QT程序中使用的ui界面就保存在该文件中 组件 设置当前组件的属性 点谁显示谁的属性 调整最终页面的布局,使组件控件在水平或对齐 调整因页面放大缩小时,控件与控件之间的水平和垂直间距 各种各样的按钮 图像显示有关的视图 列表框 各…

Gradle学习笔记之Groovy简单使用

简介 groovy可以当成java的脚本化改良版,同样运行于JVM之上,可以很好地和java代码及相关库进行交互,既可以面向对象编程,也可以用作纯粹的脚本语言。Groovy支持动态类型转换、闭包、元编程、函数式编程、默认作用域为public&…

ArcGIS基础:使用线段分割面数据操作

本操作主要是实现线要素对面要素的分割。 先看一下原始数据,如下所示,2个面,1条线,面被线贯穿过去。 首先进行【面转线】操作,以提取面要素的边界线,如下所示 提取结果如下所示: 然后进行【…

java认证与证书

本文内容主要来自《Java加密与解密的艺术》 目前主要有JKS和PEM两种编码格式文件。 JKS(Java Key Store),Java原生的密钥库/信任库文件。**PEM(Privacy Enbanced Mail,隐私增强邮件)**是使用多种加密方法提…

2022-12-04一周学习

这周基本上还是在对前端学习的更多一点,主要是之前没有重视vue3的学习,现在在补上来,学习了vue3的一些知识,前端的权限管理,设置路由守卫,pinia,还学习了redis的一些基本操作,之前只是照搬了别人…

Linux的线程创建

对于任何一个进程来讲,即便我们没有主动去创建线程,进程也是默认有一个主线程的。线程是负责执行二进制指令的,它会根据项目执行计划书,一行一行执行下去。进程要比线程管的宽多了,除了执行指令之外,内存、…

二、演练领域驱动的设计过程

一、业务分析:统一语言与事件风暴 1、统一语言: 客户明白自己的领域知识也就是业务,以及自己需要解决的问题,也叫做痛点,但是不知道技术。技术人员知道技术,但是不了解客户的业务。所以两者交流起来往往会…

[附源码]计算机毕业设计物品捎带系统Springboot程序

项目运行 环境配置: Jdk1.8 Tomcat7.0 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术: SSM mybatis Maven Vue 等等组成,B/S模式 M…

finereport公式帮助

1 if(inarray($$$,ds1.select(销售员))<$TOPN,$$$,"其他")&#xff0c;将第 N 个销售员之后的所有销售员合并为其他&#xff0c; 2 "["((roundup($$$/$num)-1)*$num1)"~"(roundup($$$/$num)*$num)"]" 3 SQL语句用if语句&#xff0c…

HTML网页设计作业:文化网站设计——基于HTML古典中国风工艺美术网页设计(9页)

&#x1f389;精彩专栏推荐 &#x1f4ad;文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业&#xff1a; 【&#x1f4da;毕设项目精品实战案例 (10…

SpringBoot @InitBinder注解绑定请求参数

参考资料 springMVC之InitBinder 和 ValidatorspringMVC之InitBinder的用法1springMVC之InitBinder的用法2 目录一. 作用二. 前期准备三. Get请求 URL传值处理3.1 前台-test16.html3.2 Controller层3.3 效果四. Post请求 表单传值 自定义日期属性绑定器4.1 前台-test16.htm…

华为机试 - 任务最优调度

目录 题目描述 输入描述 输出描述 用例 题目解析 算法源码 题目描述 给定一个正整数数组表示待系统执行的任务列表&#xff0c;数组的每一个元素代表一个任务&#xff0c;元素的值表示该任务的类型。 请计算执行完所有任务所需的最短时间。 任务执行规则如下: 任务可…