setTimeout and the Web Api
Recently I was having a tough time testing some asynchronous behaviour and used setTimeout to try to understand some of the behaviour. Things did not go as I expected and I discovered I really didn’t understand setTimeout at all.
Below is a run through of what I learned about setTimeout and the Web Api.
setTimeout
My initial understanding of setTimeout was that it delayed taking the action by however many milliseconds you put at the end. Its syntax is like this.
setTimeout(() => { console.log("I'll appear after 3 seconds")}, 3000)
so setTimeout is a function which you pass two arguments to. The first argument is a function to be invoked and the second argument is the number of milliseconds you want it to wait to invoke said function.
setTimeout(functionToExecute, millisecondsToWaitBeforeExecuting)
lets test it out
Some examples
function consoleLogTwo() {
console.log(2)
}console.log(1)
setTimeout(consoleLogTwo, 1000)
console.log(3)
So in this instance I’d expect to get back
1
3
2
as its hanging around for 1 second before executing consoleLogTwo and as such has time to go ahead and console log 3.
What if we changed the setTimeout wait period to 0.
My gross misunderstanding of how setTimeout works
Based on my previous understanding of setTimeout this line
setTimeout(consoleLogTwo, 0)
meant execute consoleLogTwo immediately and was equivalent to
consoleLogTwo()
so with the following code
function consoleLogTwo() {
console.log(2)
}console.log(1)
setTimeout(consoleLogTwo, 0)
console.log(3)
I’d expect to get back
1
2
3
HOWEVER!!!
I was very very wrong
I did not. I get back
1
3
2
again!
What is going on?
Even when I make the last step be a much longer step (printing out almost 5000 numbers)
function consoleLogTwo() {
console.log(2)
}console.log(1)
setTimeout(consoleLogTwo, 0)
for(i = 3; i < 5000; i++){ console.log(i) }
it still returns two last
1
3
4
....
4998
4999
2
I thought I’d discovered something very interesting but when I showed the rest of the developers at my work they were all terribly unimpressed and said “Well yeah, cos it has to go off to the webApi so its at the back of the queue”
Helpful resources
So I was recommended this great video
which led me to this amazing tool loupe
This visualises what is happening when your javascript code is run.
The below examples I’ve slowed down to quarter speed so its easier to see what is happening.
Here is our example with the 1 second delay
And here is our example with the 0 second delay
In both examples it adds the executable line to the calls stack. If its part of the Javascript processor it executes immediately and moves onto the next line. However if its part of the WebApi like (setTimeout) it gets sent out to the Web Api. Once its completed it then moves to the callback queue. Once the call stack is empty it pulls in from the callback queue and gets executed. The only difference between the
setTimeout(consoleLogTwo, 1000),
and
setTimeout(consoleLogTwo, 0)
is the slight delay (you see the spinner spinning) between being added from Web Api to the Callback Queue.
It doesn’t matter if there is a 0 second delay, 1 second delay or even longer, once the time elapses it still gets sent to the callback queue and can’t execute until the call stack is empty.
I’d heartily encourage you to go watch the video and have a play around with loupe. I found it super helpful in my investigation.