何时不使用承诺 [关闭]

Posted

技术标签:

【中文标题】何时不使用承诺 [关闭]【英文标题】:When NOT to use promises [closed] 【发布时间】:2016-09-28 09:06:37 【问题描述】:

在阅读了数十篇关于 es6 Promise 有多棒以及我们为什么要实现它们的文章后,我感到所有我的(非平凡的)javascript 函数都应该是 Promise。

事实上,我在使用它们编写代码时感觉很棒,因为我避免了厄运三角形,并且看似获得了清晰简洁的代码。 (它确实使关于执行的推理变得更加简单)。

我找不到的是:你什么时候使用承诺?我什么时候避免使用它们?

更新:

虽然我已经看到了 API 一致性等一些重要方面,但我还没有找到一个可靠的 NO 案例。 Lux 的回答表明,获取事件发射器的操作应该避免它们,因为重复的回调与 Promise 不兼容。然而,我确实觉得答案仍然缺乏实质内容来检查它(正确)。

【问题讨论】:

当你使用 RxJS 时:D 只要我 100% 确定我的代码将同步执行,我就会避免使用承诺。在任何其他情况下,承诺会让你的生活更轻松。 【参考方案1】:

大多数情况下,Promise 用于简化异步任务的工作。有时,我们故意异步做一些事情以避免工作线程过载,因为每个选项卡只有一个线程。当事情很小或可以由 Web Worker 处理时,就不需要 Promise。

【讨论】:

【参考方案2】:

一些经验法则:

    当您的方法可以同步(简单数据转换)时,请在该方法中使用同步代码。

    但是如果方法可以是同步的sometimes,和异步的sometimes(基于内部或外部状态的多个代码路径),它应该是异步的总是。否则,您的代码在复杂场景中的行为方式可能会遇到意想不到的细微差异,因此最好避免将这两种态度混为一谈。

    [edit] 如评论中所述,当您的方法目前是同步的,但您坚信它可能需要在未来的某个时间进行异步工作时,您可能希望从一开始就使用 Promise 以避免代价高昂的重构.

    一般来说,你的 API 应该是一致的,所以最好要么处处使用 Promise,要么处处使用回调。这将更容易推理代码。

    如果您正在编写超高性能代码和/或需要低内存占用,您可以考虑不使用 Promise 而是使用回调,或者使用专注于性能的 Promise 库,例如 bluebird,而不是原生 Promise 实现/一般用例 polyfill。

    [edit] 不管怎样,web 平台的新添加,比如全局 fetch 函数,返回一个 Promise,而且似乎在即将到来的未来越来越多的浏览器内置将运行在承诺。所以如果你愿意编写现代代码,你就不会逃避承诺。

【讨论】:

我喜欢你关于 API 一致性的观点。 对第 1 点的评论:我需要实现一个函数来验证用户的输入。目前,该函数不需要做任何异步工作,但我正在考虑返回一个 Promise ,所以如果将来需要做异步工作,我不必重写对函数的所有调用。 【参考方案3】:

您将 Promise 用于一次性异步操作。启动操作,执行操作,通知调用者完成或结果或错误,然后永久完成。

不使用承诺的情况与上述不同:

    当您的操作或功能完全同步时。将异步 API(即使使用 Promise)放在同步操作上只会让事情变得比需要的更复杂。 代替可能发生多次的事件。例如,您不会对按钮单击处理程序使用承诺。 eventEmitter 或其他类似事件的结构仍然是循环事件的更好结构。 当您遇到回调被设计为多次调用的回调情况(如报告进度或通过回调提供插件服务)。 如果您要向已经以其他方式(例如使用传统回调)设计的 API 添加一项新操作,并且需要 API 一致性。 如果您针对的是不原生支持 Promises 的旧环境(如旧浏览器),并且您正在尝试优化代码的下载大小而您只做一两个异步操作,并且您没有使用 jQuery 或 Angular 之类的东西,它们已经内置了可以使用的 Promise 形式。如果您正在执行大量异步工作,那么可能值得使用 Promises polyfill,因此这一点仅适用于大小非常重要且异步工作很少的情况。 适用于操作经常无法完成或发生的情况。 Promise 是一个有状态的对象,因此会消耗一些内存。创建数以千计的 Promise 以获取通常不会发生的许多不同事情的通知是没有意义的,因为这会创建数以千计的 Promise 对象(通常带有它们随附的闭包),而这些对象通常永远不会被使用。这只是低效的内存使用,可能通过某种事件通知更好地服务。正如我上面所说,当您启动操作、执行操作、通知调用者结果或错误时,promise 效果最佳。

【讨论】:

【参考方案4】:

如果您希望代码在浏览器中运行(可能没有内置 Promises)并且大小真的很重要,那么您可能决定不使用 Promises,因此您不能使用承诺垫片/库。

【讨论】:

今天很有趣......这个投票者有什么问题? 我认为投反对票的人投了反对票,因为在使用 Babel 和 babel-polyfill 时,使用 Promises 完全没有问题。 由于投反对票的人没有添加评论和解释,我会为你投赞成票:)。 :) 谢谢@NielsSteenbeek。大小问题仍然存在……承诺 shim 会增加你的二进制/依赖。这个模块npmjs.com/package/es6-promise-polyfill 声称与 ES6 兼容,大小为 2.6KB。如果您使用 Bluebird 等其他 Promise 库,则对大小的影响要大得多。 如果您正在做大量异步工作,即使您的目标浏览器本身不支持 Promise,也值得包含一个 Promises polyfill 库。 Promise 提供的好处绰绰有余,值得添加一个 polyfill。【参考方案5】:

Promises 有一个用例:异步结果只会出现一次。

如果可以同步返回结果,则不要使用 Promises,并且仍然需要事件回调,因为它们可能会发生多次。

【讨论】:

关于重新发生回调事件的观点非常棒!假设我想从另一个程序或库中获取结果? I/O 是一项棘手的工作,因此为了让自己感觉更安全,我会选择在这一点上一直使用 Promise。这是一个坏习惯吗?当我 100% 确定结果(或副作用)只会出现一次时,我是否应该只实施 Promise? 好吧,promise 只会触发一次。这不是一个事件! 那么,如果 promise 返回一个本身具有事件发射器的对象,而我仍然需要等到获取完成后再继续操作呢? 这可以做到,但仍然是一个问题,为什么你应该使用承诺而不是同步返回? 因为我不想阻止我的应用程序的其余部分仍然可以执行与该特定对象无关的其他任务。

以上是关于何时不使用承诺 [关闭]的主要内容,如果未能解决你的问题,请参考以下文章

React 中的悬念承诺何时执行?

Node.js:何时使用 Promises 与 Callbacks

何时使用 Redux-saga / Redux thunk 何时不使用? [关闭]

何时拒绝/解决承诺

何时不使用 lambda 表达式 [关闭]

量角器中的“defaultTimeoutInterval”何时重置?