console.log isn’t in the JavaScript language

Don’t take my word for it — RTFM!

Nikhil John
The Startup
4 min readFeb 11, 2020

--

console.log is probably one of the most used commands by JavaScript beginners and veterans alike. But it isn’t part of the JavaScript Language itself. Don’t believe me? Check out the ECMAScript® 2015 Language Specification.

Now that I have piqued your interest because you didn’t find a single mention of console in the ES6 Language Specification, read on.

Some of you might already know this, but what is called JavaScript on the Browser/Server, it is usually the JavaScript Environment. And this Environment is hardly just the Javascript Language Runtime (running on Javascript Engine i.e. V8 on Chrome and NodeJS, SpiderMonkey on Firefox, JavaScriptCore on Safari).

JavaScript Environment = JavaScript Runtime + Event Loop + External API + Callback Queue

Note: The Event Loop can be within the JavaScript Engine depending on the implementation

Illustration of JavaScript’s Concurrency Model on the browser

Theconsole object is a Web API provided by the Browser to the JavaScript Engine, much like DOM, Fetch, History, Service Workers and Web Storage APIs. This makes perfect sense when you consider the fact that as a language, JavaScript runs on various environments browser and server-side environments, each with its own console implementation.

The parts of JavaScript that are standard across all environments are detailed in the ECMA Specs (primitives, data types, language grammar and syntax, arithmetic and logical operations, built-in objects and functions, etc.). This means that while Array.isArray() is built into JS, setTimeout() and console aren’t.

Let’s look at what the implementation of console looks like across various environments:

console on Chrome v78 (left) and Node v10 (right), both running V8

The Node implementation has a couple of more methods (markTimeline, timeline, timelineEnd) than the Chrome implementation though both environments implement the same ECMA Specs. On Firefox, console will be further different from the two above.

Why is this important? To understand the workings of JavaScript, you need to have a grasp on how the language interacts with the environment it is embedded in.

In fact, JS is a fundamentally single threaded, synchronous language.

Any parts that are asynchronous (setTimeout, setInterval etc.) are implemented by and work via. the execution environment.

On the Browser, JavaScript execution looks something like this (courtesy Loupe by Philip Roberts). Note that ‘JavaScript’ or V8 is confined to the box titled ‘Call Stack’ on the left. Web APIs and the Callback Queue are both components of the Browser environment.

What is visualized above is the JavaScript Concurrency Model, or ‘How single-threaded synchronous JavaScript executes multiple (seemingly) concurrent asynchronous operations’. This also explains the infamous JavaScript interview question of why the below code

prints

and not

JavaScript executes every command synchronously, one after the other. Any statement that has a callback function (like the setTimeout) is treated no differently, but the callback function is pushed to the callback queue.

Because we now know that setTimeout is a Web API, it easier to understand that it triggers an external timer on the browser outside the JavaScript Runtime. While it may seem like JavaScript ‘revisits’ the point of execution at a later point in time, what actually happens it this:

  • …..
  • Event Loop continuously checks for non-empty Callback Queue (returns false)
  • V8 pops setTimeout function from Call Stack and executes it
  • The execution notifies V8 to call the Web API to start the external timer (ET). ET starts.
  • Event Loop continuously checks for non-empty Callback Queue (returns false)
  • V8 pops any other frames in the Call Stack and executes them.
  • …..
  • ET runs out
  • Web API pushes callback function (cbFn) into Callback Queue
  • Event Loop continuously checks for non-empty Callback Queue (returns cbFn)
  • Event Loop pushes cbFn into Call Stack
  • V8 pops cbFn from Call Stack i.e. executes it
  • Event Loop continuously checks for non-empty Callback Queue (returns nothing)
  • …..

And now we know how synchronous, single-threaded JavaScript — runs asynchronous operations. The magic sauce is external APIs.

Happy coding!

--

--

Nikhil John
The Startup

Tips and tricks on Travelling and Web Engineering! Senior Engineer @Microsoft