Well put. Good to see that Python can handle this cleanly.
You can do pretty much exactly the same with JS but I do think that there is some merit to this intermediate step of having the then() clauses for backwards-compatibility because you can't always guarantee that the caller will in be an async function.
Async/await is an all-or-nothing improvement not an incremental one.
For imperative code the goal is to write code that is just as clear as writing a single threaded algorithm: a simple list of steps. Promises and callbacks DO NOT ACHIEVE THIS GOAL.
That stackoverflow post showed a python solution that's infinitely cleaner than js. Python skipped callbacks and promise chains and jumped directly to the best way to do async operations... async/await.
You want to shove a parallel set in an async chain of operations? Here's the way to do serial and parallel async operations in Python:
You see that code? Way more clearer way more understandable than your promise chain. Python has it's problems but your promise code is not powerful at all, it leads to over complicated code and just slightly better than callbacks.