何时不使用承诺
When NOT to use promises
在阅读了数十篇关于 es6 承诺有多棒以及为什么我们应该实施它们的文章后,我感到 ALL 我的(非平凡的)javascript 函数应该是 promises。
事实上,使用它们编写代码时我感觉很棒,因为我避免了厄运三角,并且看起来代码清晰简洁。 (它确实使关于执行的推理变得更加简单)。
我没能找到的是:你什么时候不使用承诺?我什么时候避免使用它们?
更新:
虽然我看到了一些很棒的观点,比如 API 一致性,但我还没有找到一个可靠的 NO 案例。 Lux 的回答表明,获取事件发射器的操作应该避免使用它们,因为循环回调与承诺不兼容。但是,我确实觉得现在的答案仍然缺乏实质内容来检查它(是否正确)。
嗯,Promises 有一个用例:异步结果只出现一次。
如果可以 return 结果同步,则不要使用 Promises,并且您仍然需要事件回调,因为它们可能会发生多次。
如果您希望您的代码在浏览器中 运行(可能没有内置 Promises)并且大小 REALLY 很重要,您可以决定不使用 Promises , 所以你用不起 Promise shims/libs.
Promises 通常用于简化异步任务的处理。有时,我们故意异步地做一些事情以避免工作线程过载,因为每个选项卡只有一个线程。当事情很小或可以由 Web Worker 处理时,就不需要 Promises。
一些经验法则:
当你的方法可以是同步的(简单的数据转换),然后在该方法中使用同步代码。
然而,如果方法可以是同步的有时,异步的有时(基于内部或外部状态的多个代码路径),它应该是异步的 always。否则,您的代码在复杂场景中的行为方式可能会遇到意想不到的细微差异,因此最好避免混淆这两种态度。
[edit] 如评论中所述,当您的方法目前是同步的,但您坚信它可能需要在将来的某一时刻进行异步工作时,您可能希望从一开始就使用 promises 以避免昂贵的重构。
一般来说,你的API应该是一致的,所以最好要么到处使用承诺,要么到处使用回调。这将使对代码的推理变得更容易。
如果您正在编写超高性能代码 and/or 需要低内存占用,您可以考虑不使用 promises 而使用回调,或者使用专注于性能的 promise 库,例如 bluebird,而不是原生的 Promise 实现/一般用例 polyfill。
[edit] 不管怎样,web 平台的新增功能,比如全局 fetch 函数,return 一个 Promise
,似乎在即将到来的未来越来越多的浏览器内置插件将按承诺运行。因此,如果您愿意编写现代代码,就不会逃避承诺。
您将 promises 用于一次性异步操作。启动操作,执行操作,通知调用者完成或结果或错误,然后永远完成。
不使用 promises 的情况 与上述情况不同:
- 当您的操作或功能完全同步。将异步 API(即使有承诺)放在同步操作上只会让事情变得比需要的更复杂。
- 代替可以多次发生的事件。例如,您不会对按钮单击处理程序使用承诺。 eventEmitter 或其他类似事件的结构仍然是重复事件的更好结构。
- 当您遇到回调情况时,回调被设计为多次调用(例如报告进度或通过回调提供插件服务)。
- 如果您要向已经以其他方式设计的 API 添加一个新操作(例如使用传统回调)并且 API 一致性 是需要的。
- 如果您目标是较旧的环境,它们本身不支持 Promises(如旧浏览器),并且您正在尝试优化代码的下载大小,并且您只执行一个或两个异步操作,并且您没有使用 jQuery 或 Angular 之类的东西,它们已经内置了一种您可以使用的承诺形式。如果你正在做大量的异步工作,那么使用 Promises polyfill 可能是值得的,所以这一点仅适用于大小非常重要且异步工作很少的情况。
- 对于动作经常没有完成或发生的情况。 Promises 是一个有状态的对象,因此会消耗一些内存。创建数以千计的 promise 来获得通常不会发生的许多不同事情的通知是没有意义的,因为这将创建数以千计的几乎永远不会被使用的 promise 对象(通常带有它们的闭包)。这只是低效的内存使用,某种事件通知可能会更好。正如我上面所说,当您启动操作、执行操作、通知调用者结果或错误时,promises 最有效。
在阅读了数十篇关于 es6 承诺有多棒以及为什么我们应该实施它们的文章后,我感到 ALL 我的(非平凡的)javascript 函数应该是 promises。
事实上,使用它们编写代码时我感觉很棒,因为我避免了厄运三角,并且看起来代码清晰简洁。 (它确实使关于执行的推理变得更加简单)。
我没能找到的是:你什么时候不使用承诺?我什么时候避免使用它们?
更新:
虽然我看到了一些很棒的观点,比如 API 一致性,但我还没有找到一个可靠的 NO 案例。 Lux 的回答表明,获取事件发射器的操作应该避免使用它们,因为循环回调与承诺不兼容。但是,我确实觉得现在的答案仍然缺乏实质内容来检查它(是否正确)。
嗯,Promises 有一个用例:异步结果只出现一次。
如果可以 return 结果同步,则不要使用 Promises,并且您仍然需要事件回调,因为它们可能会发生多次。
如果您希望您的代码在浏览器中 运行(可能没有内置 Promises)并且大小 REALLY 很重要,您可以决定不使用 Promises , 所以你用不起 Promise shims/libs.
Promises 通常用于简化异步任务的处理。有时,我们故意异步地做一些事情以避免工作线程过载,因为每个选项卡只有一个线程。当事情很小或可以由 Web Worker 处理时,就不需要 Promises。
一些经验法则:
当你的方法可以是同步的(简单的数据转换),然后在该方法中使用同步代码。
然而,如果方法可以是同步的有时,异步的有时(基于内部或外部状态的多个代码路径),它应该是异步的 always。否则,您的代码在复杂场景中的行为方式可能会遇到意想不到的细微差异,因此最好避免混淆这两种态度。
[edit] 如评论中所述,当您的方法目前是同步的,但您坚信它可能需要在将来的某一时刻进行异步工作时,您可能希望从一开始就使用 promises 以避免昂贵的重构。
一般来说,你的API应该是一致的,所以最好要么到处使用承诺,要么到处使用回调。这将使对代码的推理变得更容易。
如果您正在编写超高性能代码 and/or 需要低内存占用,您可以考虑不使用 promises 而使用回调,或者使用专注于性能的 promise 库,例如 bluebird,而不是原生的 Promise 实现/一般用例 polyfill。
[edit] 不管怎样,web 平台的新增功能,比如全局 fetch 函数,return 一个
Promise
,似乎在即将到来的未来越来越多的浏览器内置插件将按承诺运行。因此,如果您愿意编写现代代码,就不会逃避承诺。
您将 promises 用于一次性异步操作。启动操作,执行操作,通知调用者完成或结果或错误,然后永远完成。
不使用 promises 的情况 与上述情况不同:
- 当您的操作或功能完全同步。将异步 API(即使有承诺)放在同步操作上只会让事情变得比需要的更复杂。
- 代替可以多次发生的事件。例如,您不会对按钮单击处理程序使用承诺。 eventEmitter 或其他类似事件的结构仍然是重复事件的更好结构。
- 当您遇到回调情况时,回调被设计为多次调用(例如报告进度或通过回调提供插件服务)。
- 如果您要向已经以其他方式设计的 API 添加一个新操作(例如使用传统回调)并且 API 一致性 是需要的。
- 如果您目标是较旧的环境,它们本身不支持 Promises(如旧浏览器),并且您正在尝试优化代码的下载大小,并且您只执行一个或两个异步操作,并且您没有使用 jQuery 或 Angular 之类的东西,它们已经内置了一种您可以使用的承诺形式。如果你正在做大量的异步工作,那么使用 Promises polyfill 可能是值得的,所以这一点仅适用于大小非常重要且异步工作很少的情况。
- 对于动作经常没有完成或发生的情况。 Promises 是一个有状态的对象,因此会消耗一些内存。创建数以千计的 promise 来获得通常不会发生的许多不同事情的通知是没有意义的,因为这将创建数以千计的几乎永远不会被使用的 promise 对象(通常带有它们的闭包)。这只是低效的内存使用,某种事件通知可能会更好。正如我上面所说,当您启动操作、执行操作、通知调用者结果或错误时,promises 最有效。