Allow me to make both a theoretical and practical argument.
It's been said that "callbacks are imperative; promises are functional". It's true. Furthermore, callbacks structure control flow and promises structure data flow. Instruction scheduling is an explicit sequence with callbacks (well, assuming the API calls you back precisely once), but scheduling is an implicit topological sort of the directed acyclic dependency graph of promises.
Sometimes, when it comes to side effects, implicit scheduling is less than ideal. You need specific things to happen in a specific order. The solution is to introduce data dependencies to force a particular schedule. This is precisely what is done by monads in Haskell. However, unlike Haskell, JavaScript doesn't have "do" syntax, so there's no convenient notation for a nested chain of bindings.
The result of not having monadic binding syntax is that you wind up with some funky nested chain of getY(x).then(y => y.then(z => z.then(.... OR you have to declare variables up top, flatten your then blocks in to a promise chain, and often ignore intermediate values:
let y, z;
getY(x)
.then(returnedY => { y = returnedY; return zPromise(); )
.then(returnedZ => { z = returnedZ; return ......; }
.then(......another side effect.....)
.then(_ => f(y, z))
async/await neatly eliminates this problem by reusing the traditional coupling of data flow dependencies with first-order control flow dependencies.
Practically:
let y = await getY(x);
let z = await getZ(y);
......another side effect....
return f(y, z)