非常平常的情景。我希望有一些解耦的代码,即在某些东西准备就绪时触发事件。对于整个应用程序运行,这只会发生一次。
另一方面,还有另一段代码,我想在触发两个或更多事件时发生其他事情。我的意思是像所有这些,如依赖。
好吧,更多异步的东西在一起......绝对是正确的承诺吗?
然后我开始思考。使用pub / sub进行一次性活动真的很明智吗?仅仅制定可获得的承诺会更好,一旦该事件即将被触发,该承诺就会解决吗?但是,这意味着我需要将解耦代码相互连接起来。有一件事是共享EventEmitter,但依赖于某些代码来实际创建承诺...这听起来相当糟糕。
所以我在考虑某种混合。有模块,其他模块可以要求"事件"通过它的名字和获得准备好的Promise对象。然后,其他模块应该触发该事件并以这种方式有效地完成/拒绝该事件。
var promisedLand = require('./promisedLand');
promisedLand.waitFor('event'); // returns promise
promisedLand.resolve('event', value);
promisedLand.reject('event', error);
您对此解决方案有何看法?有没有可能有这样的解决方案?
答案 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。它不是很常见尚并且它有自己的缺点,但它肯定会像你想到的那样思考。
所以,简短的回顾:
另外,你可以在不知道自己的情况下考虑自己的范例。你应该得到它,诚实。
答案 1 :(得分:2)
好吧,我已经制作了类似于问题中提出的解决方案。
欢迎来到Promised Land