Skip to content

Instantly share code, notes, and snippets.

@Raynos
Created October 14, 2012 23:05
Show Gist options
  • Star 9 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Raynos/3890101 to your computer and use it in GitHub Desktop.
Save Raynos/3890101 to your computer and use it in GitHub Desktop.

In other words, the following asynchronous code:

var d = Domain.create()

d.on("error", function (error) {
    console.error("Error with the twitterverse:", error)
})

d.enter()

getTweetsFor("domenic")
    .reduce(findMostMentioned, [])
    .map(function (mostMentioned) {
        return mostMentioned.map(function (user) { return user.username })
    })
    .toArray(function (mostMentionedNames) {
        console.log("Most mentioned names:", mostMentionedNames)
    })

d.exit()

parallels the synchronous code:

try {
    var mostMentioned = findMostMentioned(getTweetsFor("domenic"))
    var mostMentionedNames = mostMentioned.map(function (user) { return user.username })
    console.log("Most mentioned names:", mostMentionedNames)
} catch (error) {
    console.error("Error with the twitterverse: ", error)
}

Note in particular how errors flowed from any step in the process to our catch handler, without explicit by-hand bubbling code.

@domenic
Copy link

domenic commented Oct 14, 2012

You are exhibiting promises here exactly. Your getTweetsFor, reduce, and map functions are promise-returning, and toArray is just a weaker then in disguise.

@briancavalier
Copy link

Just to illustrate that this can be modeled easily using a promise chain, here it is using when.js's map+reduce. Similarly, errors always flow to error handler, without explicit/by-hand propagation.

var when = require('when');

// mostMentioned and mostMentionedNames are promises
var mostMentioned = when.reduce(getTweetsFor('domenic'), findMostMentioned, []);
var mostMentionedNames = when.map(mostMentioned, function(user) { return user.username; });
mostMentionedNames.then(function (mostMentionedNames) {
        console.log("Most mentioned names:", mostMentionedNames);
    }, function (error) {
        console.error("Error with the twitterverse:", error);
    }
);

As domenic's article says, promises are easily composable, like regular return values:

when.map(when.reduce(getTweetsFor('domenic'), findMostMentioned, []),
    function(user) { return user.username; })
.then(function (mostMentionedNames) {
        console.log("Most mentioned names:", mostMentionedNames);
    }, function (error) {
        console.error("Error with the twitterverse:", error);
    }
);

That's really the beauty of promises. They are simple building blocks that restore the familiar rules of function application & composition, and exception propagation, even in the face of asynchrony.

@Raynos
Copy link
Author

Raynos commented Oct 16, 2012

@domenic

You are exhibiting promises here exactly. Your getTweetsFor, reduce, and map functions are promise-returning, and toArray is just a weaker then in disguise.

You have it backwards.

  • promises is an eventual value or exception
  • streams is an eventual list of values or exception

Streams are the more powerful, generic format of promises.

.then is just a weaker .pipe in disguise.

@Raynos
Copy link
Author

Raynos commented Oct 16, 2012

@briancavalier @domenic

That's really the beauty of promises. They are simple building blocks that restore the familiar rules of function application & composition, and exception propagation, even in the face of asynchrony.

https://github.com/Raynos/chain-stream#example

Streams + domains do all of that and much more.

domains allow you to handle error flow however you want very granularly and not just "the then promise rules" way.

Streams allow you to handle eventual data cleanly, especially when dealing with lazy streams.

@domenic
Copy link

domenic commented Oct 18, 2012

I still maintain that you have a hammer and all you see are nails. (In this analogy, promises are a screwdriver. Both can useful for building things but nailing screws into the wall is ignoring the benefits of having them securely screwed.)

@gaearon
Copy link

gaearon commented Jun 21, 2013

That's pretty much Rx vs TPL in .NET world. I use them both happily.

@sandro-pasquali
Copy link

Promises don't enable anything new. They might be better for some developers. The pseudo-comp-sci arguments are fatuous. AOP can also be wrapped in very sexy theory about how some "rules of ideal programming" are now being properly followed, as you can do with message passing languages, and many other language types. All mothers think their baby is the cutest.

Frankly, the main concern of modern software (and hardware) is dealing with concurrency (and indeterminacy), and the Promise spec doesn't impress in terms of innovation or sophistication. As mentioned, evented stream processors are much more interesting and flexible -- really, infinitely flexible.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment