I've used promises for quite some time, but ended up going back to nodejs-style callbacks and creating a bunch of higher-order functions that makes handling that easier and reduce the boilerplate code. The two most useful ones, that really made it much easier, deal with error handling/bubbling: (CoffeeScript)
iferr = (errfn, succfn) -> (e, a...) -> if e? then errfn e else succfn a... throwerr = iferr.bind null, (e) -> throw e # To let an error bubble up, `iferr` decorates the success function and the error function, and decide which one should handle the response # This replaces `if (err) return fn err` that you see all over the place getLastTweetBody = (user, fn) -> getTweetsFor user, iferr fn, (tweets) -> expandUrlUsingTwitterApi (parseTweetsForUrls tweet), iferr fn, (url) -> doHttpRequest url, fn # To throw the errors when you don't have any other way to handle them, the function can be decorated with `throwerr` # This replaces `if (err) throw err` that you see all over the place getLastTweetBody 'domenic', throwerr (body) -> console.log body # Or just `throwerr console.log`
With those and a couple more functions, I find writing code in that style much more manageable. The code is quite readable, there isn't much boilerplate, and you don't get the overhead of promises (which persist the promise's response, making GC somewhat problematic).