Before diving in, it's good to notice a few things.
Any reader of the code snippet
let waiting = function () {
return new Promise(resolve => {
console.log('awaiting...');
setTimeout(function () { resolve(); }, 1000);
});
};
let waitingAsync = async function () {
console.log('start...');
await waiting();
console.log('stop...');
};
waitingAsync();
console.log('done...');
may be mislead to believe that the output will be
start...
awaiting...
stop...
done...
while – as you have already noted – done...
gets printed before
stop...
.
The reason is that waitingAsync();
is a call to an asynchronous function,
while console.log('done...');
is just a normal sequential/synchronous
statement that gets carried out right away.
Question 1:
waiting
is a synchronous function (because it doesn't have async
keyword) [?]
Answer:
False. The function waiting
is asynchronous – it returns
a Promise.
Question 2:
Why couldn't done...
message be awaited after completing waitingAsync
function?
Answer:
Because console.log('done...')
is not asynchronous.
(It does not return a Promise.)
Question 3:
And main question: waitingAsync
is an asynchronous function, why is
await
keyword not required when calling it?
Answer:
Well, in your example waitingAsync
does not return any value. -
If it would return a value that you care about, then you would need to await
it to get it.
(Hello world!
in my Stack Snippet below.)
Question 4:
If I can await waitingAsync()
, [the] done...
message would be printed
last [?]
Answer:
That depends on what exactly you mean. – See my Stack Snippet below!
As long as the Done!
message is printed within the same callback as the call
await waitingAsync()
, the answer is Yes!
But if you put console.log('done...?')
after the call to the asynchronous
function that encloses await waitingAsync()
then the answer is No!
When running the snippet below, pay attention to the order of the output!
Also notice how it takes 1400 ms for Promise resolved!
to show up.
function waiting () {
return new Promise(resolve => {
console.log('awaiting...');
setTimeout(function () {
resolve('Hello world!');
console.log('Promise resolved!');
}, 1400);
});
}
async function waitingAsync () {
console.log('start...');
const toBeReturned = await waiting();
console.log('stop...');
return toBeReturned;
}
(async () => {
console.log('Heads up! The next line makes an asynchronous call.');
console.log('Result: ' + await waitingAsync()); // 'Hello world!'
console.log('Done! This will be printed LAST! - Agreed?');
})();
console.log('done...?? This is LAST in the CODE. - I awaited \
"waitingAsync()" above. - So will this be printed at the very end??');
.as-console-wrapper { max-height: 100% !important; top: 0; }
The last asynchronous function is anonymous – without name – and gets
called immediately.
In fact, this is the only function that gets called directly in the snippet.
The function waitingAsync
is only called indirectly (by the anonymous
function), and the function waiting
is also called indirectly
(by waitingAsync
).
A take away lesson
Don't ever put sequential/synchronous code after and outside a call to
an asynchronous function!
You will just confuse yourself if you do. – And even if you don't get
confused, other readers of your code almost certainly will be.