关于express与koa的使用对比详解
前言
提到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的中间件模型是线性的, 也就是一个一个往下执行的, 如下图:
这么说当然是没错的, 但是当我们执行下面代码的时候可能会有那么一点小小的困惑:
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的中间件模型了:
Koa的执行流程
同样我们再Koa源码分析, 也是说过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则可以'等'异步操作. 当然你不等也没啥问题.
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对脚本之家的支持。
- MOCTF WEB 题解
- HBase行锁与MVCC分析
- HBase行锁探索
- Spring Cloud构建微服务架构:分布式服务跟踪(抽样收集)【Dalston版】
- HBase client访问ZooKeeper获取root-region-server DeadLock问题(zookeeper.ClientCnxn Unable to get data of zn
- zookeeper学习系列:四、Paxos算法和zookeeper的关系
- 有了phonegap你还android吗?
- zookeeper学习系列:三、利用zookeeper做选举和锁
- Spring Cloud构建微服务架构:分布式服务跟踪(收集原理)【Dalston版】
- zookeeper学习系列:二、api实践
- Spring Cloud构建微服务架构:分布式服务跟踪(整合logstash)【Dalston版】
- Spring Cloud构建微服务架构:分布式服务跟踪(整合zipkin)【Dalston版】
- 困扰我多年的Connection reset问题
- scala学习笔记
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法