Reputation: 14198
As we may know, var
keyword defines a variable globally, or locally to an entire function regardless of block scope. So the below code will log 5
times with the same value.
for(var i = 0; i < 5; i++){
setTimeout(() => console.log(i), 2000);
}
To visualize the above JS runtime like this
As you can see, 5 tasks in Callback Queue will wait until Call stack is empty. So after the synchronous loop is done - It means Call stack is empty in my case, then 5 scheduled tasks - console.log(i)
with the value of i
is equal to 5
will be executed. You can play around here
And what I want is to log right after i == 2
. It works as I expected.
var sleep = (ms) => new Promise(resolve => setTimeout(() => resolve(1), ms));
async function runAsync(){
for(var i = 0; i < 5; i++){
if(i == 2) await sleep(2000);
setTimeout(() => console.log(i));
}
}
runAsync();
But I'm curious how it works while I'm not sure the call stack is empty? Whether when I'm using await
, allowing the caller of the async function to resume execution, or some else?
Any explanation/visualization of image flow would be appreciated. Thanks.
Upvotes: 3
Views: 2975
Reputation: 101652
await
cedes control of the thread and allows other processes to run until the promise being awaited resolves. Even if the promise is already resolved, await
will yield to any "microtasks" that have been waiting to execute, but that's a moot point in your case because your promise takes a full two seconds to resolve.
In your case, two setTimeout
s are queued up before the await
, so they are allowed to run when the await
happens.
The timeline is basically like this:
You can see that i
is 2 when the first pair of setTimeout
s are allowed to execute, and it is 5 when the remaining 3 execute.
Here is a snippet that hopefully demonstrates the process a little better:
var sleep = (ms) => new Promise(resolve => setTimeout(() => resolve(1), ms));
async function runAsync() {
for (var i = 0; i < 5; i++) {
console.log('i is now', i);
if (i == 2) {
console.log('about to sleep');
await sleep(5000);
console.log('now done sleeping');
}
console.log('about to setTimeout. i is', i, 'right now');
setTimeout(() => {
console.log('setTimeout task running:', i, '- scheduling a new timeout.');
setTimeout(() => console.log('inner timeout:', i), 1000);
});
}
console.log('done looping. i is', i);
}
runAsync();
Upvotes: 5