背景
用Node.js开发App服务端Api.框架:Express,Promise库:bluebird.
局限
我没用过ES7的await,async语法,所以无法比较.另外,bluebird也了解的不详细,如有写的不对的地方,实属正常,欢迎讨论.
惊喜出现的过程
从callback到async
开始只用Node的传统callback嵌套方式.后来有的api终于变成了callback hell,变得难以阅读,理解,调试,于是只好寻找解决方法.首先找到了async.async没有引入新的概念,也用callback,但只用一层.开始用的还不错,用它的waterfall,parallel等控制流api组织代码块.看一个例子:
这是用async的waterfall写的不带嵌套的一个接口(每步内没有asycn的api嵌套),每步的实现收起了.基本上就是一直在查询,往respEntity的data里放数据.这样的业务逻辑用callback写已经无法忍受了,用async算是基本解决了callback hell.
从async到Promise(bluebird)
后来有些api,总体是串行结构,但有些步骤可以并行运行,得到所有结果以后再进行下一步(或总体并行,其中有串行),这就需要串并行嵌套,开始不知道async行不行,就没嵌套用,后来为了性能最优,试了一下,发现可以嵌套写,但非常痛苦.因为async每步内用的还是callback方式,一旦嵌套,就是2层callback加上2层async自身的模版代码,每步的结果还需要往后传,缠绵悱恻,完全无法直视.
于是开始学习Promise,不熟悉Promise是什么的可以看看这里,并找到了bluebird.bluebird是一个全功能的Promise库,性能据说也不错.参考官网:Why bluebird?.这个阶段持续了一段时间,用Promise.props
,Promise.all
,和then
解决了async的嵌套痛点,异步代码全部撸平.
看一个路由层串并行例子,业务逻辑:检测参数后,开始用bluebird走异步串并行,先验证用户,如果参数错误直接返回异常,否则继续并行查询2种数据,再拼结果,返回数据或中间有任意步骤出错返回异常.
1 | const uid = req.query.uid; |
从上面例子可以看出,用bluebird写异步串并行嵌套业务逻辑,使每个逻辑变成了一个独立的函数.这就使开发,调试,修改都变得轻松愉快了很多,极大提高了效率.开发过程中,完全符合人类思维过程,处理完一个,再处理下一个.整个异步过程完全可以先写出所有业务的stub函数,把路由走通,再挨个实现具体功能.调试过程理解代码和断点选择都变的一目了然.业务更改时候,不需要的串行处理只要注释掉相应的then代码块就行,不需要的并行处理只要注释掉Promise.props里对象的某一项就行.添加业务逻辑同理.
从bluebird作为异步代码工具到bluebird作为代码控制流工具
但实际工作中上面的代码模式会遇上一些问题,比如参数检查本身的异常检测和返回,经常需要不止一个.这样就需要重复写多次返回异常.加上异步部分也有返回异常,导致异常处理没那么清晰,也不符合DRY原则.有一次写了3个参数检查加三个返回,看着实在难受,于是尝试了一下把整个业务逻辑都用一句Promise串起来,用最后的catch捕获从头到尾的所有同步,异步和内部嵌套异常,发现可以,于是每个路由的主体就变成一句Promise.
惊喜: 作为代码控制流工具,把业务逻辑用一条语句串起来了
按这个思路,上面的例子可以改成这样:
1 | const uid = req.query.uid; |
其中返回异常函数sendError
可以独立成一个模块供所有路由使用,每处异常只需要定义自己的错误编码和文字,然后抛出.
1 | ; |
这样就解决了重复返回异常.
然后呢?就没有然后了,所有路由全都按这个套路重写,自我感觉逼格高了些.有些函数式连续transform数据的感觉,整个流程以请求参数为输入,以返回请求结束,一句完成,中间异步并行产生的结果通过return Promise.props()
或return单一Promise往后传,都全了在最后一个then
里整理,格式化数据返回.后面最后一个.catch
捕获所有异常.
常用的bluebird Api,参考
流控制api
then
(单一异步或同步),Promise.props
(有限个数的并行),Promise.all
,Prommise.map
(不定个数的并行)数据库api
Promise.using
(访问数据库,自动释放连接)其他
Promise.resolve()
(便于传递值),catch
(捕获异常)
希望
有很多bluebird的api,不知道干啥的,大致看了下,也没看懂,如果您有分享,一定要告诉我,万分感谢.