Eliminating the repetitive plumbing is a feature of haskell, not a feature of the monad. What the continuation monad gets you is a pipeline of asynchronous and synchronous operations. Whether or not something is asynchronous is abstracted away. Your example could be rewritten as:
composeAsync([
fetchUser("url"),
function(user) { return user.address },
fetchAddress,
function(address) { return address.zipcode }
]).then(function(output) {
document.write("Zipcode: " + output);
});
In this example you don't need to care if fetchAddress is synchronous or asynchronous, it'll work either way.Its at least worth noting that one thing Haskell gives you is the ability to perform assignment within the async functions. This is also possible with Javascript, but a bit more intuitive in Haskell. Again, this is a feature of haskell, not a feature of monads.
var outputs = {};
composeAsync([
fetchUser("url"),
function(output) { outputs['user'] = output },
function() { return outputs.user.address },
fetchAddress,
function(output) { outputs['address'] = output }
]).then(function(output) { ... });
composeAsync could also be rewritten to store this in an accumulator, making it look a little nicer.