使用promises进行一次事件处理?

时间:2014-04-16 16:38:48

标签: javascript events promise publish-subscribe

非常平常的情景。我希望有一些解耦的代码,即在某些东西准备就绪时触发事件。对于整个应用程序运行,这只会发生一次。

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

好吧,更多异步的东西在一起......绝对是正确的承诺吗?

然后我开始思考。使用pub / sub进行一次性活动真的很明智吗?仅仅制定可获得的承诺会更好,一旦该事件即将被触发,该承诺就会解决吗?但是,这意味着我需要将解耦代码相互连接起来。有一件事是共享EventEmitter,但依赖于某些代码来实际创建承诺...这听起来相当糟糕。

所以我在考虑某种混合。有模块,其他模块可以要求"事件"通过它的名字和获得准备好的Promise对象。然后,其他模块应该触发该事件并以这种方式有效地完成/拒绝该事件。

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

您对此解决方案有何看法?有没有可能有这样的解决方案?

2 个答案:

答案 0 :(得分:22)

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

让我重申一下,因为这是一个很多的误解。 Promise是不是事件发射器。随着进展,他们可能被黑客攻击成一种残缺的事件发射器,但在一天结束时。承诺不是事件发射器。

承诺

他们是什么?承诺是一个"框"超过您可以使用.then方法在某个时刻打开的值,然后将结果放在另一个框中。没什么,没什么。

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

承诺作为发射器

使用promises作为事件发射器的问题是组合,promises中的进展事件根本不能很好地构成。承诺连锁和撰写和事件不是。这就是为什么Q库倾向于推进v2中的估计。这就是ECMAScript 6中从未包含进展的原因。

事件发射器本身就是一个非常精细的抽象,当它们是建立你的关系(pub-sub)的正确工具时使用事件发射器,当他们成为正确的工具来建模时使用promises关系,当他们成为正确的关系建模工具时使用流。只是不要使用一种工具来处理所有事情,因为这(从经验中)只会给你带来很多痛苦。

我在问题中描述的内容真的很酷,那是怎么回事?

你在寻找什么?哦,那存在。它实际上非常精彩,尽管它也带有一系列问题。

您正在寻找的内容称为 FRP - 功能性反应式编程。有很多图书馆使用最好的图书馆(在我看来)是BaconJS

FRP有你正在谈论的可观察的概念。以下是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');

非常类似于链接中的承诺,但不代表直接延续,而是连续流媒体和接收器。

FRP是Haskell等函数式语言中非常常见和发展的范例,非常适用于JavaScript。它不是很常见并且它有自己的缺点,但它肯定会像你想到的那样思考。

所以,简短的回顾:

  • Promise不是事件发射器。 Promise很棒,很强大并且解决了很多有趣的并发问题 - 但它们并不是你所有解耦流量控制的灵丹妙药。
  • FRP是你提出的这个很酷的东西,但还没有制定出来。它完全按照您在问题中描述的那样具有可观察和事件的概念。

另外,你可以在不知道自己的情况下考虑自己的范例。你应该得到它,诚实。

答案 1 :(得分:2)

好吧,我已经制作了类似于问题中提出的解决方案。

欢迎来到Promised Land