Deep-dive of asynchronous programming evolution, starting from synchronous code, moving to callbacks, then promises and futures, completing with coroutines