I'm trying to wrap my head around async/await and how it works under the hood, be it JavaScript, C# or others.
From what I understand, in JavaScript at least, putting `await foo()` inside an async function, splits the calling function in two, with the 2nd half being converted to a callback. (Pretty sure this is full of errors so please correct me where I'm wrong)
Why can't non-async functions use await()?
I've also read that await() basically preempts the currently running function. How does this work?
Update: I'm re-reading http://journal.stuffwithstuff.com/2015/02/01/what-color-is-y... and I think the answer lies somewhere in this paragraph, but I can't wrap my head around it yet:
> The fundamental problem is “How do you pick up where you left off when an operation completes”? You’ve built up some big callstack and then you call some IO operation. For performance, that operation uses the operating system’s underlying asynchronous API. You cannot wait for it to complete because it won’t. You have to return all the way back to your language’s event loop and give the OS some time to spin before it will be done. Once operation completes, you need to resume what you were doing. The usual way a language “remembers where it is” is the callstack. That tracks all of the functions that are currently being invoked and where the instruction pointer is in each one. But to do async IO, you have to unwind and discard the entire C callstack. Kind of a Catch-22. You can do super fast IO, you just can’t do anything with the result! Every language that has async IO in its core—or in the case of JS, the browser’s event loop—copes with this in some way. [...]
I don't get the "You cannot wait for it to complete because it won’t." or the "But to do async IO, you have to unwind and discard the entire C callstack" parts.
I'm also using these resources, they help but I'm not there yet:
- https://stackoverflow.com/questions/47227550/using-await-ins...
- https://www.youtube.com/watch?v=KmMU5Y_r0Uk
I think what OP is assuming is a multi-threaded or multi-process environment, where the calling function can just block whatever execution context it's running in and wait until the async function returns.
The problem is that many environments are effectively non-multi-threaded, especially the (usually single) thread/queue/process that draws the UI and responds to user input. So if you block the UI thread, your whole app (at least from the standpoint of the user) stops responding.
Still, this should work in principle, but threads are more costly in terms of memory and context switching time than continuations, so it makes sense to allow the thread to continue to handle other tasks while waiting for e.g. I/O to complete.
This is what the author of the classic https://journal.stuffwithstuff.com/2015/02/01/what-color-is-... settles on as the best way of handling async tasks, but I recall there being some pushback on that here on HN.