关于express与koa的使用对比详解


Posted in Javascript onJanuary 25, 2018

前言

提到Node.js开发,不得不提目前炙手可热的2大框架express和koa。Express诞生已有时日,是一个简洁而灵活的web开发框架,使用简单而功能强大。Koa相对更为年轻,是Express框架原班人马基于ES6新特性重新开发的敏捷开发框架,现在可谓风头正劲,大有赶超Express之势。

Express和koa都是服务端的开发框架,服务端开发的重点是对HTTP Request和HTTP Response两个对象的封装和处理,应用的生命周期维护以及视图的处理等。

Express主要基于Connect中间件框架,功能丰富,随取随用,并且框架自身封装了大量便利的功能,比如路由、视图处理等等。而koa主要基于co中间件框架,框架自身并没集成太多功能,大部分功能需要用户自行require中间件去解决,但是由于其基于ES6 generator特性的中间件机制,解决了长期诟病的“callback hell”和麻烦的错误处理的问题,大受开发者欢迎。

以前其实写过一篇express和koa的对比, 但是后来发现里面有不少谬误. 所以一直惦记着纠正一下之前的错误, 尤其关于中间件部分的对比.

这里的express就拿更加简单的connect代替

connect的执行流程
通常我们都说connect的中间件模型是线性的, 也就是一个一个往下执行的, 如下图:

关于express与koa的使用对比详解

这么说当然是没错的, 但是当我们执行下面代码的时候可能会有那么一点小小的困惑:

const connect = require('connect')
const app = connect()
app.use(function m1 (req, res, next) {
 console.log('m1')
 next()
 console.log('m1 end')
})
app.use(function m2 (req, res, next) {
 console.log('m2')
 next()
 console.log('m2 end')
})
app.use(function m3 (req, res, next) {
 console.log('m3')
 res.end('hello')
})
app.listen(8080)

当我们访问http://127.0.0.1:8080的时候, 控制台会打印如下:

m1
m2
m3
m2 end
m1 end

这么个结果跟我们上面的模型似乎有点出入, 不是说线性的吗, 为什么next后面的代码还会继续执行? 当然这个我们再之前已经有过结论了, 有兴趣的可以详细瞧瞧, 我们现在直接拿来结果, connect的中间件模型伪代码表示如下:

http.createServer(function (req, res) {
 m1 (req, res) {
 m2 (req, res) {
 m3 (req, res) {}
 }
 }
})

可以看到就是一层一层嵌套的回调, 那么再把我们之前有点疑问的代码简化一下:

http.createServer(function (req, res) {
 console.log('m1')
 m1 (req, res) {
 console.log('m2')
 m2 (req, res) {
 m3 (req, res) {
 console.log('m3')
 res.end('hello')
 }
 }
 console.log('m2 end')
 }
 console.log('m1 end')
})

千万别被上面的回调绕晕了, 就是很简单的回调函数, 一切都解释的通了: 即使res.end之后, 我们的代码还是要继续往下走的, 可以这么说connect的中间件其实也是洋葱形的, 但是因为作为同步代码, 一般不回这么做罢了, 那么上面我们可以重现描述一下connect的中间件模型了:

关于express与koa的使用对比详解

Koa的执行流程

同样我们再Koa源码分析, 也是说过Koa的中间件模型: 洋葱形

关于express与koa的使用对比详解

以下面代码为例:

const Koa = require('koa')
const app = new Koa()
app.use(async function m1 (ctx, next) {
 console.log('m1')
 await next()
 console.log('m1 end')
})
app.use(async function m2 (ctx, next) {
 console.log('m2')
 await next()
 console.log('m2 end')
})
app.use(async function m3 (ctx) {
 console.log('m3')
 ctx.body = 'hello'
})
app.listen(8080)

访问服务, 输出:

m1
m2
m3
m2 end
m1 end

emm 貌似跟connect没差别, 之前看过一篇文章, 实验到这里得到了一个koa和express的中间件模型没差别的结论, 包括我也是很迷惑, 当然是有差别的, 结论后面讲. 同样这里直接拿出koa中间件的简化模型:

Promise.resolve(async m1 () {
 console.log(m1)
 await Promise.resolve(async m2 () {
 console.log(m2)
 await Promise.resolve(async m3 () {
 console.log(m3)
 ctx.body = 'xxx'
 })
 console.log(m2 end)
 })
 console.log(m1 end)
})

我们知道async/await的作用是'同步化'异步操作(看上去如此, 其实不是, 但是我们不需要去管), 那这里的Promise理所当然的被'同步'了, 也就是说console.log(m3 end)的一切异步操作都可以'同步化'.

结论

说出结论之前我们其实可以想一下, 既然connect的中间件也是洋葱形的, 那么跟koa一样的用法似乎也没啥毛病, 那么我来设想一下, 我们的服务需要取数据库里的的一个用户假设是getUser吧, getUser当然是异步的. 分别来看看connect和koa的做法吧:

// connect
app.use(function (req, res) {
 getUser(user => res.end(user))
})
// Koa
app.use(async (ctx) => {
 const user = await getUser()
 ctx.body = user
})

当然这么看似乎没啥差别. 那直接给出结论吧(憋): connect的中间件是同步, 不会'等'其他异步操作, koa则可以'等'异步操作. 当然你不等也没啥问题.

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对三水点靠木的支持。

Javascript 相关文章推荐
使用JQUERY Tabs插件宿主IFRAMES
Jan 01 Javascript
单击按钮显示隐藏子菜单经典案例
Jan 04 Javascript
基于JavaScript实现继承机制之构造函数方法对象冒充的使用详解
May 07 Javascript
JS获取当前网址、主机地址项目根路径
Nov 19 Javascript
Javascript 学习笔记之 对象篇(二) : 原型对象
Jun 24 Javascript
Bootstrap CSS组件之输入框组
Dec 17 Javascript
JavaScript中Math对象的方法介绍
Jan 05 Javascript
react实现点击选中的li高亮的示例代码
May 24 Javascript
Vue封装的可编辑表格插件方法
Aug 28 Javascript
vue移动端html5页面根据屏幕适配的四种解决方法
Oct 19 Javascript
微信小程序与webview交互实现支付功能
Jun 07 Javascript
微信小程序页面间传递数组对象方法解析
Nov 06 Javascript
在vue项目创建的后初始化首次使用stylus安装方法分享
Jan 25 #Javascript
Vue框架之goods组件开发详解
Jan 25 #Javascript
前端MVVM框架解析之双向绑定
Jan 24 #Javascript
JS运动特效之完美运动框架实例分析
Jan 24 #Javascript
JS运动特效之同时运动实现方法分析
Jan 24 #Javascript
JS运动特效之链式运动分析
Jan 24 #Javascript
Bootstrap popover 实现鼠标移入移除显示隐藏功能方法
Jan 24 #Javascript
You might like
自定义PHP分页函数
2006/10/09 PHP
PHP持久连接mysql_pconnect()函数使用介绍
2012/02/05 PHP
PHP实现表单提交数据的验证处理功能【防SQL注入和XSS攻击等】
2017/07/21 PHP
ASP SQL防注入的方法
2008/12/25 Javascript
jQuery 开天辟地入门篇一
2009/12/09 Javascript
js判断某个方法是否存在实例代码
2015/01/10 Javascript
jQuery入门介绍之基础知识
2015/01/13 Javascript
JS控制网页动态生成任意行列数表格的方法
2015/03/09 Javascript
javascript实时显示北京时间的方法
2015/03/12 Javascript
jQuery实现横向带缓冲的水平运动效果(附demo源码下载)
2016/01/29 Javascript
JS从数组中随机取出几个数组元素的方法
2016/08/02 Javascript
浅谈js对象的创建和对6种继承模式的理解和遐想
2016/10/16 Javascript
Bootstrap实现翻页效果
2017/11/27 Javascript
javascript按顺序加载运行js方法
2017/12/01 Javascript
详解vue-router数据加载与缓存使用总结
2018/10/29 Javascript
vue分页器组件编写方法详解
2019/06/28 Javascript
使用element-ui +Vue 解决 table 里包含表单验证的问题
2020/07/17 Javascript
python爬虫之百度API调用方法
2017/06/11 Python
Python分析学校四六级过关情况
2017/11/22 Python
今天 平安夜 Python 送你一顶圣诞帽 @微信官方
2017/12/25 Python
TensorFlow模型保存和提取的方法
2018/03/08 Python
使用Eclipse如何开发python脚本
2018/04/11 Python
Python3.5常见内置方法参数用法实例详解
2019/04/29 Python
Falsk 与 Django 过滤器的使用与区别详解
2019/06/04 Python
django drf框架中的user验证以及JWT拓展的介绍
2019/08/12 Python
解决python-docx打包之后找不到default.docx的问题
2020/02/13 Python
python zip,lambda,map函数代码实例
2020/04/04 Python
Python 操作 PostgreSQL 数据库示例【连接、增删改查等】
2020/04/21 Python
美国高端医师级美容产品电商:BeautifiedYou.com
2017/04/17 全球购物
联想马亚西亚官方网站:Lenovo Malaysia
2018/09/19 全球购物
香港莎莎官网Sasa.com:亚洲著名国际化妆品商城
2019/11/10 全球购物
汽车维修专业毕业生的求职信分享
2013/12/04 职场文书
教学实习自我评价
2014/01/28 职场文书
项目采购员岗位职责
2014/04/15 职场文书
nginx常用命令放入shell脚本详解
2021/03/31 Servers
python自动获取微信公众号最新文章的实现代码
2022/07/15 Python