关于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 相关文章推荐
JS 日期验证正则附asp日期格式化函数
Sep 11 Javascript
IE8 中使用加速器(Activities)
May 14 Javascript
JavaScript.The.Good.Parts阅读笔记(二)作用域&闭包&减缓全局空间污染
Nov 16 Javascript
JS重要知识点小结
Nov 06 Javascript
js图片延迟加载的实现方法及思路
Jul 22 Javascript
javascript实现的一个带下拉框功能的文本框
May 08 Javascript
第一次接触神奇的Bootstrap网格系统
Jul 27 Javascript
基于input框覆盖掉数字英文的实例讲解
Jul 21 Javascript
详解react-native WebView 返回处理(非回调方法可解决)
Feb 27 Javascript
详解在微信小程序的JS脚本中使用Promise来优化函数处理
Mar 06 Javascript
关于vue里页面的缓存详解
Nov 04 Javascript
Vue的data、computed、watch源码浅谈
Apr 04 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
c#中的实现php中的preg_replace
2009/12/21 PHP
PHP命名空间和自动加载类
2016/04/03 PHP
使用PHPStorm+XDebug搭建单步调试环境
2017/11/19 PHP
Yii2处理密码加密及验证的方法
2019/05/12 PHP
Ctrl+Enter提交内容信息
2006/06/26 Javascript
用js实现下载远程文件并保存在本地的脚本
2008/05/06 Javascript
IE6,IE7下js动态加载图片不显示错误
2010/07/17 Javascript
jQuery的实现原理的模拟代码 -1 核心部分
2010/08/01 Javascript
在vs2010中调试javascript代码方法
2011/02/11 Javascript
JS中setInterval、setTimeout不能传递带参数的函数的解决方案
2013/04/28 Javascript
JQuery设置和去除disabled属性的5种方法总结
2013/05/16 Javascript
JS弹出层单纯的绝对定位居中示例代码
2014/02/18 Javascript
淘宝网提供的国内NPM镜像简介和使用方法
2014/04/17 Javascript
jQuery使用hide方法隐藏页面上指定元素的方法
2015/03/30 Javascript
基于 Node.js 实现前后端分离
2016/04/23 Javascript
js获取鼠标点击的对象,点击另一个按钮删除该对象的实现代码
2016/05/13 Javascript
jQuery实例—选项卡的简单实现(js源码和jQuery)
2016/06/14 Javascript
jQuery弹出窗口简单实现代码
2017/03/09 Javascript
node版本管理工具n包使用教程详解
2018/11/09 Javascript
通过Nodejs搭建网站简单实现注册登录流程
2019/06/14 NodeJs
vue iview多张图片大图预览、缩放翻转
2019/07/13 Javascript
[04:29]2014DOTA2国际邀请赛 主赛事第三日TOPPLAY
2014/07/21 DOTA
[50:59]2018DOTA2亚洲邀请赛 4.7 总决赛 LGD vs Mineski第四场
2018/04/10 DOTA
python追加元素到列表的方法
2015/07/28 Python
Python双精度浮点数运算并分行显示操作示例
2017/07/21 Python
TensorFlow利用saver保存和提取参数的实例
2018/07/26 Python
详解python 利用echarts画地图(热力图)(世界地图,省市地图,区县地图)
2019/08/06 Python
tensorflow实现二维平面模拟三维数据教程
2020/02/11 Python
基于python实现操作git过程代码解析
2020/07/27 Python
Python Map 函数的使用
2020/08/28 Python
移动端开发HTML5页面点击按钮后出现闪烁或黑色背景的解决办法
2018/09/19 HTML / CSS
Timberland法国官网:购买靴子、鞋子、衣服、夹克和配饰
2019/11/30 全球购物
外贸实习生自荐信范文
2013/11/24 职场文书
党校毕业心得体会
2014/09/13 职场文书
初中优秀学生评语
2014/12/29 职场文书
vue特效之翻牌动画
2022/04/20 Vue.js