[ANN] eventflow - Add asynchronous abilities to your EventEmitters

180 views
Skip to first unread message

Brian Link

unread,
Jan 14, 2013, 7:21:58 PM1/14/13
to nod...@googlegroups.com
Over the past few months I've been using this little utility module in my applications.  Thought I would share it here now that it is stable and well-documented.

https://github.com/cpsubrian/node-eventflow

EventFlow exposes some of the great flow-control utility provided by caolan's async module in the form of events.  Basically, you'll be able to 'register' asynchronous (or sync, or a mix) handlers via the `emitter.on()` syntax you are already familiar with.  Then you can fire them with `emitter.series()`, `emitter.parallel()`, `emitter.waterfall()`, etc.

The docs should explain it all but I'm happy to answer any questions here.  Its got tests, travis-ci peace-of-mind, and has been in production on several apps for a few months.

Enjoy!

leei

unread,
Jan 15, 2013, 2:08:19 PM1/15/13
to nod...@googlegroups.com
Totally fills a gap for me.  In the couple of cases I've needed something like this, it is always a pain to come up with alternatives to the basic EventEmitter model.

Thank you.

Brian Link

unread,
Jan 15, 2013, 4:08:54 PM1/15/13
to nod...@googlegroups.com
Glad you find it useful.  Let me know if you end up needing some of the other async methods or if anything else comes up.

Katsumoto

unread,
Jan 15, 2013, 5:35:31 PM1/15/13
to nod...@googlegroups.com
I'm using the same flow for almost a year in my framework. 

Brian Link

unread,
Jan 15, 2013, 5:48:50 PM1/15/13
to nod...@googlegroups.com
Very cool.  I've been loving this pattern. Bright minds ...

Jake Verbaten

unread,
Jan 16, 2013, 1:54:31 AM1/16/13
to nod...@googlegroups.com
You guys realize that using events to effectively call a series of functions in parallel or series is abuse of the event emitter right.

What your doing there is RPC over events. RPC is best done with something like functions or methods

If an event handler can error you need to put down your EventEmitter and think about your code and how to structure it.


--
Job Board: http://jobs.nodejs.org/
Posting guidelines: https://github.com/joyent/node/wiki/Mailing-List-Posting-Guidelines
You received this message because you are subscribed to the Google
Groups "nodejs" group.
To post to this group, send email to nod...@googlegroups.com
To unsubscribe from this group, send email to
nodejs+un...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/nodejs?hl=en?hl=en

Ken

unread,
Jan 16, 2013, 1:27:27 PM1/16/13
to nod...@googlegroups.com
Can you expound on this, particularly why it's an "abuse"?  I've been using this technique in an ad hoc manner with apparent success, and find it much less convoluted (and, at least at first glance, more "node-ish") than the other async/promise/... libraries which get promoted here from time to time.  I find it particularly useful during server startup, when I have a bunch of tasks (reading config, fetching many documents from a variety of remote databases, warming caches, etc.) that have a mix of serial/parallel relationships.  I've actually thought for some time that it would be handy if EventEmitter had native support for at least the parallel case (i.e. a flavor of listener that fires after all of a list events have occurred, or a certain number of one event).  --Ken

Katsumoto

unread,
Jan 16, 2013, 6:59:41 PM1/16/13
to nod...@googlegroups.com
What abuse or problem could be here if this is normal async flow, event handler could return error as first argument.

среда, 16 января 2013 г., 8:54:31 UTC+2 пользователь Raynos написал:

Alan Hoffmeister

unread,
Jan 16, 2013, 7:09:28 PM1/16/13
to nodejs
Well, I think Jake was talking about queuing the callbacks and waiting for the event to return back and fire those callbacks. This is a pattern that I try to avoid inside Node.js because of the potential memory leaking probability.

What if something went wrong and the event never "ping back"? Your callback will stay there ocuping memory.

--
Att,
Alan Hoffmeister


2013/1/16 Katsumoto <shog...@gmail.com>

Katsumoto

unread,
Jan 16, 2013, 7:35:17 PM1/16/13
to nod...@googlegroups.com
четверг, 17 января 2013 г., 2:09:28 UTC+2 пользователь Alan Hoffmeister написал:

Well, I think Jake was talking about queuing the callbacks and waiting for the event to return back and fire those callbacks. This is a pattern that I try to avoid inside Node.js because of the potential memory leaking probability.

This is quite different, the method you talk about allow only to run list of handlers you know. Is easy to handle with async[series || parallel || waterfall].
But this approach allow to fire an event and listeners that you've even didn't know about may do they work async and callback so app could run his next step.
 
What if something went wrong and the event never "ping back"? Your callback will stay there ocuping memory.

The same we could talk about any other mistake, same thing goes if someone does something wrong...

Mark Hahn

unread,
Jan 16, 2013, 8:07:10 PM1/16/13
to nodejs
The problem with using things for purposes not intended, or designed for, may work great.  The problem is that in the future they may change.  No one is going to worry about supporting an odd use like this.

Jake Verbaten

unread,
Jan 16, 2013, 10:11:16 PM1/16/13
to nod...@googlegroups.com
The event interface is simple.

I module X emit an event. module Y listens to the event and does something.

module Y does NOT in whatever way or form return a value from the event. Event emitters are not a bidirectional communication channel. They are a single direction communication channel.

module Y does NOT return a value or an error through a callback you emit on the event. Doing so is doing RPC. `foo.emit("doSomething", data, function (err) { ... })` is wrong and should be `foo.doSomething(data, function (err) { ... })`

The most important thing is that event emitters is a single direction communication. If you want bidirectional communication use a duplex stream or functions

Brian Link

unread,
Jan 17, 2013, 1:43:09 AM1/17/13
to nod...@googlegroups.com
I think what you guys are missing is that no one said these are event emitters.  They extend event emitters to provide a new pattern for register sync/async handlers.  Of course if the EventEmitter object changes in core, EventFlow will have to adapt .. and thats what tests are for.

> What if something went wrong and the event never "ping back"?

This is no different than any other callback.  If your callback never gets called.. of course you are screwed... and you the programmer screwed up.

Not really interested in getting into the usual async flame-war here.  Either you find the lib useful or you dont.  I love it and it makes some patterns that I use really easy to implement.  Happy to get constructive feedback but if you think the approach is an 'abuse', dont use it :)

Brian Link

unread,
Jan 17, 2013, 1:48:06 AM1/17/13
to nod...@googlegroups.com
> The most important thing is that event emitters is a single direction communication. If you want bidirectional communication use a duplex stream or functions

This is all that is happening here.  We have an array of functions that get called either in parallel or series.  Its convenient that the EventEmitter object already has support for storing arrays of functions associated with a string key.  So.. I'm using it :)

Jake Verbaten

unread,
Jan 17, 2013, 10:06:58 PM1/17/13
to nod...@googlegroups.com
If you emit a callback on an event then its bidirectional and not an event.

By all means make a new thing but don't call it an eventemitter.


--

Brian Link

unread,
Jan 18, 2013, 1:09:31 AM1/18/13
to nod...@googlegroups.com
I don't quite get the academic disagreement.  Its an EventEmitter, literally .. you can on/emit like usual.  If you like, you can register async handlers (fine, not 'events').  You could identify those handlers with a prefix if you are concerned about mixups (e.g. `emitter.on('hook:validate')`).

I'll concede that this debate has sparked some ideas of better separating the 'handlers' from the regular 'events'.  It might be more generically useful (and safer from programmer errors) if it served as more of a mix-in that you would add on to an EventEmitter (or any other object) and the api was name-spaced.  Something like:

```
var emitter = new require('events').EventEmitter();
require('eventflow')(emitter);

// Adds (don't like 'flow', but works for illustration)
emitter.flow.handle('validate', function (model, [cb]) { ... });
emitter.flow.series();
emitter.flow.parallel();
// etc.
```

I'd probably still use an EventEmitter internally to take advantage of on(), setMaxListeners(), removeAllListeners(), etc.
Reply all
Reply to author
Forward
0 new messages