My issue with async/await specifically, and promises generally is that it blurs the line between a value and a value object. If you think about Promise { value }
it becomes very important whether a function returns a value or a promise wrapped value. Unfortunately, JS promises don't behave like category theory objects (so much for the myriad of Promises are Monads
blogposts) and will resolve nested values until done or rejected. This can make reasoning about their behaviour tricky and makes writing types for their functions tougher as well.
Let's start with my ideal in JS, just using promises:
/* pretend these functions are network calls, hence the promise.resolve */
const producesA = () => Promise.resolve(1);
const producesB = a => Promise.resolve(a + 1);
const doSomething = (a, b) => Promise.resolve(a + b);