【问题标题】:One time event handling using promises?使用 Promise 进行一次性事件处理?
【发布时间】:2014-04-16 16:38:47
【问题描述】:

非常常见的场景。我想要一些解耦的代码,即在准备就绪时触发事件。对于整个应用程序运行,这只会发生一次。

另一方面,还有一段代码,我希望在触发两个或多个事件时发生其他事情。我的意思是像所有这些,像依赖项。

好吧,更多异步的东西在一起......肯定是对的?

然后我开始思考。将 pub/sub 用于一次性事件真的很明智吗?仅仅做出可访问的承诺会不会更好,一旦该事件即将被触发就会解决?但是,这意味着我需要将解耦的代码互连起来。一件事是共享 EventEmitter,但依赖于一些代码来实际创建 Promise ......这听起来很糟糕。

所以我正在考虑某种组合。拥有模块,其他模块可以通过其名称请求“事件”并获得准备好的 Promise 对象。然后其他模块应该触发该事件并以这种方式有效地履行/拒绝该事件。

var promisedLand = require('./promisedLand');
promisedLand.waitFor('event'); // returns promise
promisedLand.resolve('event', value);
promisedLand.reject('event', error);

您如何看待这个解决方案?有没有可能已经有这样的解决方案了?

【问题讨论】:

    标签: javascript events promise publish-subscribe


    【解决方案1】:

    好问题。让我从一件事开始:Promise 不是事件发射器。

    让我重申一下,因为这是一个经常出现的误解。 Promise 是不是事件发射器。随着进程的进展,它们可能会被黑客入侵成一种残缺的事件发射器,但最终还是会如此。 Promise 不是事件发射器。

    承诺

    它们是什么? Promise 是一个值的“盒子”,您可以在某个时候使用.then 方法打开它,然后将结果放入另一个盒子中。不多也不少。

    就像你说的,承诺是一次性的。如果您的活动是一次性活动 - 那么承诺绝对可以。从本质上讲,您的事件是一种不测事件,并且承诺在大多数情况下会更好地对其进行建模。

    作为发射器的承诺

    使用 Promise 作为事件发射器的问题在于组合,Promise 中的进程事件根本没有很好地组合。 Promise 链和组合,而事件则没有。这就是为什么 Q 库在 v2 中放弃进度以支持估计的原因。这就是 ECMAScript 6 中从未包含进程的原因。

    事件发射器本身就是一个完美的抽象,当它们是建模关系的正确工具时使用事件发射器(pub-sub),当它们是建模关系的正确工具时使用承诺,使用流当它们是建模您的关系的正确工具时。只是不要对所有事情都使用一种工具,因为这(根据经验)只会给你带来很多痛苦。

    我在问题中描述的内容真的很酷,那又如何?

    您在寻找什么?哦,那是存在的。虽然它也有自己的一系列问题,但实际上它非常棒。

    您正在寻找的东西称为 FRP - 函数式反应式编程。有很多图书馆可以做到这一点,其中最好的(在我看来)是 BaconJS

    FRP 有你所说的 observables 的概念。以下是来自BaconJS 网站的计数器示例:

    var up   = $('#up').asEventStream('click');
    var down = $('#down').asEventStream('click');
     
    var counter =
      // map up to 1, down to -1
      up.map(1).merge(down.map(-1))
      // accumulate sum
        .scan(0, function(x,y) { return x + y });
     
    // assign observable value to jQuery property text
    counter.assign($('#counter'), 'text');
    

    与链式中的 promise 非常相似,但不代表直接延续,而是连续流式传输和接收器。

    FRP 是 Haskell 等函数式语言中非常常见和开发的范例,在 JavaScript 中非常适用。这还不是很常见,它有自己的缺点,但它肯定像你的想法一样思考。

    所以,简短回顾一下:

    • Promise 不是事件发射器。 Promise 非常棒,可以解决很多有趣的并发问题 - 但它们并不是所有解耦流控制的灵丹妙药。
    • FRP 是您想出但尚未制定的这个很酷的东西。它具有与您在问题中描述的完全相同的可观察对象和事件的概念。

    此外,您可以在自己不知道范式的情况下思考范式,为自己拍拍背。老实说,这是你应得的。

    【讨论】:

    • 哇,答案真的很详细,谢谢!谈论作为发射器的承诺是没有必要的。正如问题主体所述,我主要担心那些计时器。我也不喜欢使用进度,实际上我大部分时间都没有使用进度。用例场景可能很少,但这确实很少。我一定会去看看 BaconJS,因为这对我来说是非常新的模式。
    • @FredyC FRP 非常酷。我之所以强调承诺不会成为发射器的原因是因为很多用户最终经常阅读这些问题。即使您非常了解 Promise 和发射器以及它们的用例 - 我敢打赌很多其他读者都不会 :) 享受您的 FRP 之旅 :)
    • 这看起来是一个非常好的概念,尤其是像fromPromisefromEventTarget 这样的方法。我可能应该提到我正在寻找 NodeJS 应用程序的解决方案,但幸运的是它支持两者。惊人的。你让我开心:)
    • 我让another question 更加关注 FRP,因为看起来,我可能缺少一些明显的 FRP 解决方案 :)
    • 培根肯定会在我的代码的其他一些地方找到更频繁地发布事件的地方。我想我必须自己在中间编写那个模块,但应该很容易。
    【解决方案2】:

    好的,我自己的解决方案类似于问题中提出的解决方案。

    欢迎来到Promised Land

    【讨论】:

    • 应许之地正是我想要的!
    猜你喜欢
    • 2014-02-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-22
    • 1970-01-01
    • 2018-05-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多