前言
天冷了,唯有学习来温暖自己。
最近利用业余的时间,跟着 coderwhy 老师学习 node.js,了解以及掌握一些服务端的常见知识:
- fileSystem:文件读取模块。
- events:事件流
- Buffer:node 中处理二进制的方式
- http 创建服务器
- Stream流的读写操作
- …
确实学习到了很多东西,填充了自己的知识体系的未知领域。
node.js 也许是前端开发者踏入服务端开发的最好选择。同样的 JavaScript,同样的语法,以及同样的你,基本上可以达到无缝衔接的开发。
对于 node.js 而言,社区里面出现了非常多的框架,快速上手,敏捷开发。
koa
和 express
就是其中的比较两个突出的框架。
在阅读下文之前,希望你掌握了 express 和 koa 的基本使用,不然下面内容对你的帮助也许不是那么的大。
koa 和 express 的介绍
express 是一个基于 node.js 平台,快速,开放,极简的 web 开发框架。express 官网
koa 是基于 node.js 平台的下一代 web 开发框架。koa 官网
两个框架都是同一个团队开发的,都是 node.js 中比较优秀的框架。
都是 node.js 框架,同一个团队为什么要开发两个呢?
扫描二维码关注公众号,回复: 14687810 查看本文章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:我俩的发动机都是中间件
,我有三个兄弟:request
,response
,next
,你有几个兄弟呢?
koa:额,我有两个兄弟:context
,next
。不过我这 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 异步
来分析了中间的执行顺序,可以得出两点结论:
- 无论是 express 还是 koa,当中间件是同步代码并且调用了 next 函数,那么程序运行就会先执行每个中间件next函数之前的代码,当执行到最后一个中间件时,又会回滚执行每个中间件next 函数后的代码(类似于 数据结构中的
first in last out
)。 - 无论是 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 之间的差异。
比较差异并不是为了证明谁好谁弱,而是为了另一方面来充分认识框架隐藏的知识点,加深自己理解。
若你觉得有误,请指出;若对你有用,请点个赞。