cujojs / when

A solid, fast Promises/A+ and when() implementation, plus other async goodies.
Other
3.44k stars 396 forks source link

Converting nodejs async to when #163

Closed cyberwombat closed 11 years ago

cyberwombat commented 11 years ago

Having a little trouble figuring out the proper way to do this using When:

Async1(function(err, res) {
  Async2(res, function(error, result) {
    done();
  })
})

I've got var a1 = nodefn.call(Async1); but not sure how to get 'res' from there?

briancavalier commented 11 years ago

Here you go:

// Looks a lot like plain old functional composition:
// call Async1 first, then pass it's result as a param when calling Async 2:
var promiseForResultOfAsync2 = nodefn.call(Async2, nodefn.call(Async1));

If you need to call done at the end, no matter what, regardless of success or error and don't care about result, as your example shows, you can use ensure. (FYI, typically a function like done that you use to signal the end of an async operation simply isn't needed with promises, but it depends on the situation, of course).

nodefn.call(Async2, nodefn.call(Async1)).ensure(done);

It all gets even better if you use lift to create promise-aware functions from node-style functions:

var pAsync1 = nodefn.lift(Async1);
var pAsync2 = nodefn.lift(Async2);

// Now it all looks like regular function calls
var promiseForResultOfAsync2 = pAsync2(pAsync1());

// Or, if you need done()
pAsync2(pAsync1()).ensure(done);

This is one of the great things about promises ... they take the nested continuation passing style of asynchrony, and give you back regular call-and-return style programming. Only at the point of needing to observe the ultimate result of a computation do you need to use .then() or .ensure(), etc.

EDIT: Fixed use of pAsync[1,2]

cyberwombat commented 11 years ago

Fantastic - I really appreciate you taking the time!

cyberwombat commented 11 years ago

If I wanted to do something with "res" before I pass it to Async2, what would be the approach? Say I needed to pass res.something

briancavalier commented 11 years ago

Lots of options :) Here's a few that are equivalent:

function getSomething(res) { return res.something; }

// Given the lifted pAsync1 and pAsync2 from above
var promiseForResult = pAsync1().then(getSomething).then(pAsync2);

// Equivalent, but imho, less intuitive
var promiseForResult = pAsync2(pAsync1().then(getSomething));

Of course, you can lift getSomething as well, so that it can accept a promise as a arg!

var fn = require('when/function');

var getSomething = fn.lift(function(res) { return res.something; }); // getSomething can accept a promise for its arg

// Now they all compose
var promiseForResult = pAsync2(getSomething(pAsync1()));

Depends on the situation as to whether you want/need to take it that far, of course. Good to have options tho :)

cyberwombat commented 11 years ago

Super helpful. I think I am making promises more complicated than I need to. This makes total sense.

briancavalier commented 11 years ago

No worries :) Promises can take a while to get your head around, for sure. Once you do, though, you're right, they can make things much simpler. Please also feel free to ask promise-related questions in the cujoJS google group, or in #cujojs on freenode IRC.