How about waiting until all or part of donut pack is eaten by multiple eaters? Jokes aside, async/await comes from easier handling of a callback code and automatic function splitting. Writing asynchronous donut eating in loops or with yielding of partial results is very easy to swallow with such syntactic sugar. The whole model is very easy to grasp and to work with. I'm not saying that's the best solution but it definitely works well.
Regarding stickiness of function colors - it never happens when async/await is used correctly (in the same principle as IO monad isn't sticky).
Doesn't matter. You either wait until donut is eaten by others or you don't. Caller is deciding if it's "synchronous" (blocking) action or not.
The question is how you translate mental models from real world to the code, and async/await fails here spectacularly. It's just weirdly unnatural thinking about sequencial processes. It requires tremendous amount of cognitive gymnastics just to reason about simple things.
I’m sorry but isn’t this exactly how async/await works from the perspective of the caller? If you want to wait until the donut is eaten you `.await`. If you don’t, you do other stuff and then join the future later. The fact that the executor can get other stuff done while you’re awaiting the donut consumption is largely invisible from the caller’s perspective.
That's only if you marked function with "async". Developer who writes code for "eating a donut" supposedly has better knowledge of how I'm supposed to eat it - synchonously or asynchronously. So if they didn't mark function as "async" I can't decide how I should eat it, it's decided for me.
You can eat it in the same thread. Some frameworks do that implicitly (even without await) . You can also control if it's consumed in particular thread or thread pool and decide which thread should continue. More, you can chain and/or parallelize it with other async and not-async functions without any effort. Additionally, you can handle errors and exceptions same as it's async and not-async function. Every good async/await framework offers that out of the box. More, some frameworks abstract executors and you can run the function remotely or even persist it with context. Of course you can achieve all that without async/await, but it makes that extremely easy.
Regarding stickiness of function colors - it never happens when async/await is used correctly (in the same principle as IO monad isn't sticky).