10

Pretty much usual scenario. I want to have some decoupled piece of code, that is triggering event when something is ready. This will happen only once for the whole application run.

On other side, there is another piece of code, where I want something else to happen when two or more events are triggered. I mean like all of them, like dependencies.

Alright, more async things together ... definitely promises right ?

Then I started thinking. Is it really wise to use pub/sub for one time events ? Wouldn't be better to just make accessible promise, that resolves once that event is about to be triggered ? However that would mean I need to kinda interconnect that decoupled code. One thing is having shared EventEmitter, but being dependent on some code to actually create promise ... that sounds rather bad.

So I am thinking about some kind of mix. Having module, where other modules can ask for "event" by it's name and obtaining prepared Promise object. Other module should then trigger that event and effectively fulfilling/rejecting that event this way.

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

What do you think about this solution ? Any chance there is some solution like this already available ?

FredyC
  • 3,999
  • 4
  • 30
  • 38

2 Answers2

24

Good question. Let me start by one thing: Promises are not event emitters.

Let me reiterate that, since it's a misconception that comes a lot. Promises are not event emitters. With progression, they can be hacked into a form of crippled event emitter but at the end of the day. Promises are not event emitters.

Promises

What are they? Promises are a "box" over a value which you can open at some point using the .then method and then put the result in another box. Nothing more, nothing less.

Like you said, promises are one time. If your event is a one time event - then promises are definitely ok. Essentially, your event is an eventuality and promises model it better most of the time.

Promises as emitters

The problem with using promises as event emitters is composition, progression events in promises simply did not compose very well. Promises chain and compose and events don't. This is why the Q library is dumping progression in favor of estimation in v2. This is why progression was never included in ECMAScript 6.

Event emitters are a perfectly fine abstraction on their own, use event emitters when they're the right tool to model your relation (pub-sub), use promises when they're the right tool to model your relation, use streams when they're the right tool to model your relation. Just don't use one tool for everything as this (from experience) will bring you nothing but a lot of pain.

What I described in my question is really cool though, what about that?

What you're looking for? Oh, that exist. It's quite wonderful actually though it also comes with its own sets of problems.

What you're looking for is called FRP - functional reactive programming. There are a lot of libraries that do that with the best one (in my opinion) being BaconJS.

FRP has the notion of observables you were talking about. Here is an example of a counter from the BaconJS website:

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');

Very similar to promises in chaining, but does not represent a direct continuation but a continuous streaming and a sink.

FRP is a very common and developed paradigm in functional languages like Haskell, and is very applicable in JavaScript. It's not very common yet and it has its own shortcomings, but it definitely thinks like what you had in mind.

So, short recap:

  • Promises are not event emitters. Promises are awesome and majestic and solve a lot of interesting concurrency problems - but they are not a silver bullet for all your decoupled flow control.
  • FRP is this cool thing you came up with but didn't formulate yet. It has a notion of observables and events exactly as you described in your question.

Also, you can pat yourself on the back for thinking about a paradigm without knowing it on your own. You deserve it, honest.

Community
  • 1
  • 1
Benjamin Gruenbaum
  • 270,886
  • 87
  • 504
  • 504
  • Whoa, that's really elaborate answer, thanks! It wasn't really necessary to talk about promises as emitters. As the question subject states, I am worried mainly about those one timers. I don't like using progression either and actually I am not using progression most of the time. There might be few use case scenarios, but that's really sparse. I will definitely check out that **BaconJS** as this is pretty much new pattern to me. – FredyC Apr 16 '14 at 18:12
  • 1
    @FredyC FRP is pretty cool. The reason I emphasized promises not being emitters so much is because lots of users end up reading these question often. Even if you understand promises and emitters really well and the use case of each - I'll bet you a lot of other readers don't :) Enjoy your FRP journey :) – Benjamin Gruenbaum Apr 16 '14 at 18:19
  • 1
    That looks like really nice concept, especially methods like `fromPromise` and `fromEventTarget`. I should have probably mention that I am looking for the solution for the NodeJS app, but luckily it supports both. Awesome. You made my day :) – FredyC Apr 16 '14 at 18:22
  • I have made [another question](http://stackoverflow.com/questions/23118648/handle-multiple-one-time-events-with-frp?lq=1) more FRP focused because as it seems, I am probably missing some obvious solution with FRP :) – FredyC Apr 16 '14 at 19:40
  • Bacon will definitely find the place in some other places of my code where the events are published more often. Guess I would have to write that module in the middle by myself, but should be pretty easy. – FredyC Apr 16 '14 at 19:51
  • I know it's been a while but I have trouble understanding the terms **progression** and **estimation** in the context of events and promises. I googled them along with Q but couldn't get satisfying results. May I ask you to post an adequate link? That'd be great! –  May 22 '16 at 18:35
  • @Iven you can safely ignore them it doesn't look like either are going to happen. – Benjamin Gruenbaum May 23 '16 at 06:34
  • Can you elaborate on the problems with FRP? – NSjonas Nov 07 '16 at 20:26
2

Alright, I have made my own solution similar to the one presented in the question.

Welcome to the Promised Land

FredyC
  • 3,999
  • 4
  • 30
  • 38