But isn't the same true with go channels ? If you want to asynchronously interact with a channel (that is, without blocking the main thread), you have to do it in a go block and the caller has to do the same and so on ?
Promises behave similarly - must wrap your code in promises all the way.
These constructs are alternatives to the good old callbacks, which force you to write your code inside callbacks, thus 'infecting' everything and leading to callback hell.
This 'cascade infection' effect is due to the inherent nature of things happening asynchronously, which contradicts the synchronous program flow inside a thread, so when the async event terminates, the program has to jump to a handler in order to process the results.
In the end it's a matter of taste imo..