DEV Community

Cover image for Let me understand how JavaScript works under the hood

Let me understand how JavaScript works under the hood

İnanç Akduvan on September 28, 2022

Did you ever wonder what's going on behind the scenes when you run a very small piece of code in JavaScript? I actually didn't for a long time. I...
Collapse
 
sainig profile image
Gaurav Saini • Edited

Very nice explanation!

One small addition that I'd like to make is "Hoisting". Even before the code execution begins, all variable and function declarations are hoisted (in simpler terms, moved) to the top of the file.
Looking at your very first example, if we make a small change to the code, like so

const totalApples = 10;
const totalBananas = 5;

const totalFruits = getTotalFruits();

function getTotalFruits() {
   return totalApples + totalBananas;
}
Enter fullscreen mode Exit fullscreen mode

Even though it may seem a bit counter-intuitive, the code still runs exactly as before. This is because the function declaration is moved to the top of the file before execution. Note that only declarations are hoisted, and not definitions, so if you're assigning any values to some variables, the assignments still stay in the place where you wrote them, it's just that the declaration statement with an undefined value is moved to the top of the file.

Speaking of declarations vs. definitions, one little caveat that has caught me off guard in the past, is with arrow functions. In the above code getTotalFruits is a function, since it is declared with the function keyword, but if we change it to an arrow function,

const getTotalFruits = () => {
   return totalApples + totalBananas;
};
Enter fullscreen mode Exit fullscreen mode

the code throws a ReferenceError. This is because, getTotalFruits is now technically a regular variable which is assigned an anonymous function.

Hope you and anyone reading find this useful.
Cheers!

Collapse
 
gnio profile image
Gnio

Genius

Collapse
 
inancakduvan profile image
İnanç Akduvan • Edited

Very useful addition, Gaurav! You enlightened us. Definitely I benefit from your explanation.

Thank you for your contribution 🤟

Collapse
 
mrwensveen profile image
Matthijs Wensveen

Very cool, thanks!

Question: what if we put the console.log(..) statement before fetchData.then(..)? The call stack is empty after console.log and even though the fetchData promise is already done, we haven't put showData on the microtask stack, so runTimer will be first?

Collapse
 
inancakduvan profile image
İnanç Akduvan • Edited

Hi, thanks!

If I understand the question, I will try to explain.

Settimeout, console.log, fetch... this is the calling order in your question.

First Scenerio: Fetching takes 200ms time and consoling takes 250ms:
-- setTimeout communicates with Web API
-- console.log is in Call Stack. [0ms]
-- runTimer is ready waiting in Callback Queue [0ms]
-- fetch communicates with Web aPI [1ms]
-- showData is ready waiting in Microtask Queue [200ms]
-- console.log run and consoled and removed from Call Stack [250ms]
-- showData run in Call Stack [251ms]
-- runTimer run in Call Stack [252ms]

Second Scenerio: Fetching takes 300ms time and consoling takes 250ms:
-- setTimeout communicates with Web API
-- console.log is in Call Stack. [0ms]
-- runTimer is ready waiting in Callback Queue [0ms]
-- fetch communicates with Web aPI [1ms]
-- console.log run and consoled and removed from Call Stack [250ms]
-- runTimer run in Call Stack [251ms]
-- showData is ready waiting in Microtask Queue [300ms]
-- showData run in Call Stack [301ms]

I guess, it is something like that. :)

Collapse
 
mrwensveen profile image
Matthijs Wensveen

Interesting. The second scenario is clearly correct because the fetchData promise isn't done when console.log finishes, so runTimer gets picked up from the callback queue.

I'm not so sure about the first scenario... Suppose you never call fetchData.then(showData) then showData will never run (obviously). Now, suppose you keep the fetchData promise object around for a while, do a bunch of stuff (a for loop logging "hello" to the console a few thousand times), and only then call fetchData.then(showData). Surely, the runTimer callback would have had the chance to get picked up from the callback queue, after one of the console.log("hello") calls in the loop, when the call stack is empty, and there's nothing on the microtask queue yet.

My version: Fetching takes 200ms time and consoling takes 250ms:
-- setTimeout communicates with Web API
-- console.log is in Call Stack. [0ms]
-- runTimer is ready waiting in Callback Queue [0ms]
-- fetch communicates with Web aPI [1ms]
-- console.log run and consoled and removed from Call Stack [250ms]
-- runTimer run in Call Stack [251ms]
-- fetchData promise puts showData on microtask queue [251ms]
-- showData is ready waiting in Microtask Queue [251ms]
-- showData run in Call Stack [251ms]

Maybe I should just test it and post the results here :)

Thread Thread
 
inancakduvan profile image
İnanç Akduvan • Edited

You might be right 🙂 but probably, Call Stack will never be empty during the for loop. Therefore runTimer cannot find a chance to jump in Call Stack.

One of the reasons that I guess like that:
for loop is inside Call Stack as a whole code block, so while passing from one console.log to another one, Call stack is not actually empty at any moment.

But as you said, the best way to learn is testing. If you test it, please let us know the results here ✌️

Collapse
 
quanghm27 profile image
quanghm27

Thank you so much, it's worth reading

Collapse
 
inancakduvan profile image
İnanç Akduvan

Thank you 🙏

Collapse
 
fruntend profile image
fruntend

Сongratulations 🥳! Your article hit the top posts for the week - dev.to/fruntend/top-10-posts-for-f...
Keep it up 🫰

Collapse
 
inancakduvan profile image
İnanç Akduvan

Thank you for sharing 🤟✌️

Collapse
 
shammisharma profile image
shammisharma

very well explained. Thanks.
Understanding these basics save you a lot of trouble later. Been there 😅

Collapse
 
inancakduvan profile image
İnanç Akduvan

I totally agree with this 🙂 thank you!

Collapse
 
dhruvjoshi9 profile image
Dhruv Joshi

probably the best explanation!

Collapse
 
inancakduvan profile image
İnanç Akduvan

thank you Joshi! 🙂

Collapse
 
ljq0226 profile image
ljq0226

amazing!
Thank you for sharing!

Collapse
 
damla_kker_f09b6fb1f63f6 profile image
Damla köker

Amazing! Thank you :)

Collapse
 
inancakduvan profile image
İnanç Akduvan

Thanks! 🙏

Collapse
 
imdevyoussefshaaban profile image
Youssef Shaaban

Thanks for the explanation, really clear and straight forward.

Collapse
 
inancakduvan profile image
İnanç Akduvan

Glad to hear you liked it, thanks!

Collapse
 
zakariya09 profile image
Zakariya Khan

Very nice and simple explanation! I like it. ❣️

Collapse
 
inancakduvan profile image
İnanç Akduvan

Glad you like it, thanks Zakariya 🙏