JavaScript Internals: Under The Hood of a Browser

How your code is executed inside a browser

Vlad Ostrenko
Jun 30, 2019 · 8 min read
Image for post
Image for post

Intro

Javascript is weird. Some people love it, others hate it. It has a lot of unique mechanisms which are not present and have no counterparts in other popular languages. Code execution order, for instance, which might be sometimes unintuitive, definitely stands out.

  • Browser runtime — concurrency models, event loops, and blocking and non-blocking code.

JavaScript Engine

The most popular JavaScript engine is V8 which is written in C++ and used by Chromium-based browsers such as Chrome, Opera, and even Edge.

Compilation

When your JavaScript file is loaded by the browser, V8's parser transforms it into an abstract syntax tree (AST). This tree is used by Ignition —an interpreter which produces bytecode. Bytecode is an abstraction of machine code able to be executed by compiling to non-optimized machine code. V8 executes it in the main thread while TurboFan, the optimizing compiler, makes some optimizations in another thread and produces optimized machine code.

Image for post
Image for post

Call Stack

JavaScript is a single-threaded programming language with a single call stack. It means that your code is executed synchronously. Whenever a function runs, it will run entirely before any other code runs.

  • argument parameters
  • return address
Image for post
Image for post
Call Stack in Chrome Dev Tools

Heap

Sometimes V8 doesn’t know at compile time how much memory an object variable will need. All the memory allocation for such data happens in the heap — unstructured region of memory. Objects on the heap live on after we exit the function that allocated the memory.

Image for post
Image for post
Heap snapshot in Chrome Dev Tools (2.2 MB for a blank page!)

Browser Runtime

So V8 can execute JavaScript according to the standard, synchronously, using a single call stack. But there is not much we can do with it. We need to render the UI. We need to handle user interactions with the UI. Moreover, we need to handle user interactions while making network requests. But how do we achieve concurrency when all our code is synchronous? It’s possible thanks to the browser engine.

Image for post
Image for post
Call Stack with timeout in Chrome Dev Tools

Concurrency

Right after the setTimeout function is executed — the browser engine places setTimeout’s callback function into an event table. It’s a data structure which maps registered callbacks to events, in our case onTimeout function to timeout event.

const fn1 = () => console.log('fn1')
const fn2 = () => console.log('fn2')
const callback = () => console.log('timeout')
fn1()
setTimeout(callback, 1000)
fn2()
// output:
// fn1
// fn2
// timeout
Image for post
Image for post
const fn1 = () => console.log('fn1')
const fn2 = () => console.log('fn2')
const onTimeout = () => console.log('timeout')
const onResolve1 = () => console.log('resolved1')
const onResolve2 = () => console.log('resolved2')
fn1()
setTimeout(onTimeout, 0)
Promise.resolve()
.then(onResolve1)
.then(onResolve2)
fn2()// output:
// fn1
// fn2
// resolved1
// resolved2
// timeout
Image for post
Image for post

Blocking vs Non-Blocking

In simple terms, all the JavaScript code is considered blocking. While V8 is busy with processing stack frames — the browser is stuck. The UI of your app is blocked. The user won’t be able to click, navigate, or scroll. Responses from your network requests won’t be processed until V8 finishes its work.

const fn1 = () => console.log('fn1')
const onResolve = () => console.log('resolved')
const parseImage = () => { /* long running parsing algorithm */ }
fn1()
Promise.resolve().then(onResolve) // or any other Web API async fn
parseImage()
Image for post
Image for post

Outro

Understanding what the JavaScript environment is composed of is crucial for every developer who wants to be able to solve complex tasks. Now we know how asynchronous JavaScript works, the role of the call stack, event loop, event queue and job queue in its concurrency model.

Better Programming

Advice for programmers.

Sign up for The Best of Better Programming

By Better Programming

A weekly newsletter sent every Friday with the best articles we published that week. Code tutorials, advice, career opportunities, and more! Take a look

By signing up, you will create a Medium account if you don’t already have one. Review our Privacy Policy for more information about our privacy practices.

Check your inbox
Medium sent you an email at to complete your subscription.

Vlad Ostrenko

Written by

Software developer

Better Programming

Advice for programmers.

Vlad Ostrenko

Written by

Software developer

Better Programming

Advice for programmers.

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store