我有一些旧的Node.js代码,我正在更新 . 在这个过程中,我正在设计新模块以使用旧代码 . 我现在发现,与我第一次写这篇文章时相比,我更依赖于使用ES6承诺而不是回调 . 所以现在我有一些函数混合返回promises和一些回调 - 这是乏味的 . 我认为最终应该重构使用promises . 但在此之前......
什么样的承诺是首选的,哪些是首选的回调?
是否有任何类型的情况,回调可以比承诺更好地处理,反之亦然?
根据我到目前为止看到的情况,我真的看不出任何使用回调而不是承诺的理由 . 真的吗?
3 回答
首先,您几乎不想编写混合回调和承诺进行异步操作的代码 . 如果您转向承诺或引入一些承诺,那么您可能希望将相同代码段中的回调重构为promise . 对于适当类型的操作,承诺比普通回调有许多优点,在已经在代码区域中工作时转换的努力是值得的 .
Promises are great for:
监控同步操作
只需要通知一次(通常是完成或错误)
协调或管理多个异步操作,例如排序或分支异步操作或同时管理飞行中的多个操作
从嵌套或深度嵌套的异步操作传播错误
准备好使用async / await的代码(或现在使用它与转换器一起使用)
适合Promise模型的操作只有三种状态:
pending
,fulfilled
和rejected
以及状态从pending => fulfilled
或pending => rejected
过渡的情况不能改变(单个单向转换) .动态链接或链接异步操作(例如执行这两个异步操作,检查结果,然后根据中间结果确定要执行的其他异步操作)
管理异步和同步操作的混合
自动捕获并向上传播异步完成回调中发生的任何异常(在普通回调中,这些异常有时会以静默方式隐藏) .
Plain callbacks are good for things that promises cannot do:
同步通知(例如
Array.prototype.map()
的回调)可能多次出现的通知(因此需要多次调用回调) . Promise是一次性设备,不能用于重复通知 .
无法映射到待处理,已履行,拒绝的单向状态模型的情况 .
而且,我还要添加
EventEmitter
.EventEmitters are great for:
发布/订阅类型通知
具有事件模型的接口,特别是当事件可以多次发生时(如流)
当第三方代码想要参与或监视某些内容而没有任何API而不是eventEmitter时,松散耦合 . 无需设计API . 只需将eventEmitter设为public并定义一些事件以及随之而来的数据 .
Notes about converting plain callback code to Promises
如果你的回调符合调用约定的节点,并将回调作为最后一个参数传递并调用,如此
callback(err, result)
,那么你有点自动将父函数包装在node.js中的util.promisify()
的promise中,或者如果使用Bluebird promise library,则使用Promise.promisify() .使用Bluebird,您甚至可以同时实现整个模块(在node.js调用约定中使用异步回调),例如:
In node.js version 8+
现在
util.promisify()
会将使用node.js异步调用约定的异步函数转换为返回promise的函数 .the doc:中的示例
它们都存在解决同样的问题,处理异步函数的结果 .
回调往往更加冗长,并且如果除了知道异步操作如何工作之外还需要任何额外的理解,那么同时协调多个异步请求会导致callback hell .
Promise更常见,因为它们需要更少的代码,更具可读性,因为它们像同步函数一样编写,具有单个错误通道,可以处理抛出的错误并且在最新版本的Node.js中添加了util.promisify(),可以转换Error-First回应承诺 . 现在还有
async/await
也是making its way into Node.js,它们也与Promises接口 .这完全是基于意见的,所以它真的是关于你最熟悉的东西,但Promises和
async/await
是回调的演变并增强了异步开发体验 . 无论如何,这并不是一次详尽的比较,而是对回调和承诺的高级评价 .我不记得从哪里得到这些东西,但可能有助于更好地理解承诺 .
承诺不是回调 . promise表示异步操作的未来结果 . 当然,按照你的方式写它们,你得到的好处不大 . 但是如果按照它们的使用方式编写它们,您可以以类似于同步代码的方式编写异步代码,并且更容易遵循: ADVANTAGES 1.回调的可读性2.容易捕获错误 . 3.同时回调
1. Readability over callbacks Promise提供了一种更简洁明了的方式来表示javascript中的顺序异步操作 . 它们实际上是用于实现与回调相同效果的不同语法 . 优点是提高了可读性 . 像这样的东西
比将每个单独的函数作为回调传递一样,可读性更高
2. Easy to catch errors. 当然,代码不多,但更具可读性 . 但这不是结束 . 让我们发现真正的好处:如果您想检查任何步骤中的任何错误怎么办?用回调来做这件事就好了,但是有了承诺,这是小菜一碟:
3. Simultaneous callbacks And even better: 如果那些对api,api2,api3的3个调用可以同时运行(例如,如果它们是AJAX调用)但你需要等待三个呢?没有承诺,你应该创造某种反击 . 承诺,使用ES6符号,是另一块蛋糕,非常整洁:
希望你现在以新的眼光看待Promise .