What hasn't been mentioned in this discussion are the use-case implications of the behaviour. The key thing, as I see it, is to consider what you are planning to do with the output from the top level, truly asynchronous function, and where you are planning to do that.
If you are planning to consume the output immediately, i.e. within the "async" function that is awaiting the return of the top level asynchronous function, and what you do with the output has no implication for other functions deeper in the call stack, then it does not matter that the deeper functions have moved on. But if the output is needed deeper in the call stack, then you need use "async" functions making await calls all the way down the stack to that point. Once you reach a point in the call stack where the function does not care about the asynchronous output, then you can stop using async functions.
For example, in the following code, function B uses the stuff returned from function A so is declared "async" and awaits A(). Function C() calls B(), is returned a Promise, but can move straight on before that promise is resolved because it is not interested in A()'s stuff, nor what's done with it. So C does not need to be declared as async, nor await B().
function A() {
return new Promise((resolve, reject) => {
//do something slow
resolve (astuff)
}
}
async function B() {
var bstuff = await A();
dosomethingwith(bstuff);
return;
}
function C() {
B();
dontwaitmoveon();
...
return;
}
In this next example, C() does use A()'s stuff, so needs to wait for it. C() must be declared "async" and await B(). However D() does not care about A()'s stuff, nor what's done with it, so moves on once C() returns its promise.
function A() {
return new Promise((resolve, reject) => {
//do something slow
resolve (astuff)
}
}
async function B() {
var bstuff = await A();
dosomething();
return bstuff;
}
async function C() {
var cstuff = await B();
dosomethingwith(cstuff);
...
return;
}
function D() {
C();
dontwaitmoveon();
...
return;
}
Since figuring this out, I have tried to design my code so the stuff returned by the asynchronous function is consumed as close as possible to the source.