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:
async def main():
# run them sequentially (but the loop can do other stuff in the meanwhile)
body1 = await get_body('http://httpbin.org/ip')
print body1
body2 = await get_body('http://httpbin.org/user-agent')
print body2
# run them in parallel
task1 = get_body('http://httpbin.org/ip')
task2 = get_body('http://httpbin.org/user-agent')
for body in await asyncio.gather(task1, task2):
print(body)
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.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.
You can build really complex dynamic async chains in JS very easily because of this. It's hard to explain why it's so nice until you try it.
In JS, I can do something like:
Promise.resolve().then(() => {
}) .then((resultOfLastSerialOperation) => { }) .then((parallelOp1Result, parallelOp2Result) => { });