Not necessarily! If you have a language with stackful coroutines and some scheduler, you can await promises anywhere in the call stack, as long as the top level function is executed as a coroutine.
Take this hypothetical example in Lua:
function getData()
-- downloadFileAsync() yields back to the scheduler. When its work
-- has finished, the calling function is resumed.
local file = downloadFileAsync("http://foo.com/data.json"):await()
local data = parseFile(file)
return data
end
-- main function
function main()
-- main is suspended until getData() returns
local data = getData()
-- do something with it
end
-- run takes a function and runs it as a coroutine
run(main)
Note how none of the functions are colored in any way!
For whatever reason, most modern languages decided to do async/await with stackless coroutines. I totally understand the reasoning for "system languages" like C++ (stackless coroutines are more efficient and can be optimized by the compiler), but why C#, Python and JS?
Take this hypothetical example in Lua:
Note how none of the functions are colored in any way!For whatever reason, most modern languages decided to do async/await with stackless coroutines. I totally understand the reasoning for "system languages" like C++ (stackless coroutines are more efficient and can be optimized by the compiler), but why C#, Python and JS?