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 ?
They can handle multiple asynchronous operations easily and provide better error handling than callbacks and events. In other words also, we may say that, promises are the ideal choice for handling multiple callbacks at the same time, thus avoiding the undesired callback hell situation.
To support error handling, Promise objects provide a catch() method. This is a lot like then() : you call it and pass in a handler function. However, while the handler passed to then() is called when the asynchronous operation succeeds, the handler passed to catch() is called when the asynchronous operation fails.
A promise represents the completion of an asynchronous function. It is an object that might return a value in the future. It accomplishes the same basic goal as a callback function, but with many additional features and a more readable syntax.
A promise is used to handle the asynchronous result of an operation. JavaScript is designed to not wait for an asynchronous block of code to completely execute before other synchronous parts of the code can run. With Promises, we can defer the execution of a code block until an async request is completed.
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.
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.
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 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:
Also, you can pat yourself on the back for thinking about a paradigm without knowing it on your own. You deserve it, honest.
Alright, I have made my own solution similar to the one presented in the question.
Welcome to the Promised Land
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With