For instance with Q.all, you'd do with:
return Q.all([ eventualAdd(2, 2), eventualAdd(10, 20) ]).then(function(values) { console.log(values[0], values[1]); });
can instead be
eventualAdd(2, 2). and(eventualAdd(10,20)). then(function(a, b) { console.log(a, b); });
which I feel reads nicer and gives you the results in a more usable form (something that would require another call, Q.spread, in Q). This also allows complex composition. Say you want to run 4 functions A, B, C and D, such that A and B are called together, C is called when A returns, then D is called when B and C both return. This is clumsy to do on Q, requiring packing promises into an array, etc.
The other big thing is error handling. In Q, if you forget to set an error handler at the end of the chain or explicitly set the default handler with .done(), errors go unhandled. This is clumsy; in fact the Q documentation says:
"This is a stopgap. We are exploring ways to make unhandled errors visible without any explicit handling."
We've implemented this in andthen. If there's no error handler and execution reached the end of the chain, it will be thrown so Node or the browser will print it.
There's fulfilment as well, but I get your point about putting this better in the README.