How a lightweight single threaded scripting language evolved to revolutionize the way we develop software
By: Sachin Sadasivan
Tags: JavaScript, Node, Programming, Software Development

New-fangled languages and technologies emerge, thrive and disappear often in the software development landscape. Yet a relatively lightweight single threaded simple scripting language evolved to revolutionize the way we develop software. If a programmer went hibernation from programming a decade ago for some stage reason come back now and see JavaScript, his most likely reaction would be: “What…!?!”

He would be amazed to see web developers using JavaScript engines to run their enterprise servers, desktop application developers building Whether predication application using Node.js, not to mention mobile app developers using jQuery Mobile or React Native.

He probably would go fainted to see Node Package Manager (NPM) and NPM registry!

There are several reasons behind this incredible evolution of JavaScript in the last decade or so. Here I explain few truly fascinating features of modern JavaScript that helped it to gain popularity in software development with astonishing speed.

Simplicity

As a programming language, JavaScript has always maintained its simplicity and forgiveness to programmers and their mistakes. In many instances, JavaScript gently forgives the basic programming errors like forgetting to pass a parameter to a function. It will either ignore or relay on undefined to help you manage execution of your program with a minimum level of consistency and reliability.

Consider the below simple example:

function greetAnyOne(name, greeting, place){

console.log("Hello " + name + ", " + greeting + " " + place);

}

If a developer forgot to place the argument “place” at the end of the greetAnyOne() function, JavaScript will still execute the program and produce the output by replacing “undefined” for missing argument.

greetAnyOne("Tom", "welcome to") #Output: Hello Tom, welcome to undefined

Like in life, this level of forgiveness may create troubles for JavaScript engine and that is where tools and frameworks like TypeScript come for rescue.

Typescript

TypeScript is an opensource language developed by Microsoft. TypeScript is a typed superset of JavaScript.

Types provide a way to describe the shape of an object, providing better documentation, and allowing to validate that your code is working correctly. All valid JavaScript code is also TypeScript code. TypeScript code transpliles to plain JavaScript. That way we developer get the benefits of features during development and browsers get the code they still understand.

Since TypeScript is strongly typed, everything has a datatype. This enables us to develop great tooling like:

Inline documentation

Syntax checking

Code navigation

Advanced refactoring

TypeScript implements ES 2015 Class based object orientation like classed, Objects, Interfaces and Inheritance.

TypeScript thus became one of the pillars of some of the most remarkable JavaScript frameworks like Angular.

Single threaded

Yes, you read it right, JavaScript is single threaded! You must be wondering how in this universe JavaScript enable us to develop enterprise level software applications, not to mention building highly asynchronous Webservers. Webservers are historically known to be multithreaded to serve all the concurrent client requests.

Now let’s examine how standard JavaScript engine works.

JavaScript Engine

The JavaScript engine consists of two main components

Memory heap

Memory allocation happens in heap

Call stack

Call stack is where stack frames live as code executes. It is a data structure which holds the program execution. The features of Call stack is:

Has a single call stack

Can only do one thing at a time

Execution proceeds as follows

Function is called and placed at top of call stack Function returns it is popped off the call stack

Consider the execution of the following code:

function boilWater() {

console.log("Water boiled!")

}



function addTeaBag() {

console.log("Teabag added!") ;

}



function prepareTea() {

boilWater();

addTeaBag();

console.log("Tea Prepared!")

}



prepareTea();

When the engine begins execution the call stack will be empty. Each entry on the call stack is called a stack frame.

When the engine starts executing the above code:

Starts with calling the function prepareTea()

This function intern calls boilWater() and addTeabag()

At every step of the execution, these function gets added to the Call Stack

They all are serial

Running code on a single thread has benefits, like no need to deal with resource contention and race conditions.

Running code on a single thread, however, has limitations too. What happens if a particular JavaScript function is slow?

While the Call Stack has functions to execute, the browser can’t do anything else. It is blocked it cannot render or run any other code

Consider the following code:

function boilWater() {

console.log("Water boiled!")

}

function addTeaBag() {

// No teabag found!

// Go, buy teabags from supermarket(from a remote server in software apps)

// Wait for teabag purchase...

console.log("Teabag added!");

}

function prepareTea() {

boilWater();

addTeaBag(); // Blocking call, the next code block need wait!

console.log("Tea Prepared!")

}



prepareTea();

In this case function addTeaBag() is a blocking function. Every code intended to execute next needs to wait until the function addTeaBag() returns it’s value. The browser can’t do anything else; it is blocked! It cannot render or run any other code

Modern JavaScript engines overcome this limitation by the elegant JavaScript Event Loop architecture.

JavaScript Event loop

The Event Loop has the following simple job:

Monitor the call stack and the callback queue If the call stack is empty, take the first event from the queue and push it to the call stack, which effectively runs it

This iteration is called a tick in the Event Loop.

Let’s rewrite our previous code with JavaScript Event Loop.

function boilWater() {

console.log("Water boiled!")

}



function addTeaBag() {

return function () {

// Go, buy teabags from a remote server or shop!

console.log("Teabag added!")

};

}



function prepareTea() {

boilWater();

setTimeout(addTeaBag(), 5000);

console.log("Tea Prepared!")

}



prepareTea();

Here we use the setTimeout() function which ensure the function addTeaBag() is executed asynchronously — without blocking any other functions in the stack as shown in the below image.

Thus, this architectures is one of the cornerstones that makes JavaScript a truly single threaded non-blocking asynchronous concurrent language.

Frequent releases with powerful features

JavaScript is the language for the web and is executed by all browsers. Yet there was no continues release and update cycles until a decade ago. Things have changed now dramatically, however.

JavaScript language specification is officially called as ECMAScript (ES). Up until recently, the ES versions were defined by a sequential number. ES 3 is supported by older browsers. ES5 is supported by most modern browsers.

The ES6 specification was renamed ES 2015 and introduced many new key features such as Classes and Arrow functions. Since then a new version of the specification is released each year.

If a browser cannot support the latest JavaScript specification, that needs to be transpired to older JavaScript.

This frequent releases with powerful features make JavaScript a great choice for enterprise software development at scale.

Brower Developer Tools and Debugging

Most modern browsers provide excellent developer tools to monitor and debug JavaScript while its running. A console tab in the developer tools is always the first page to look at when we see HTML and JavaScript in action.

We can put breakpoint and debug while the code runs in production. We can even modify and experiment with Document Object Model (DOM) elements while in action.

These are few outstanding features of JavaScript and its tooling around which revolutionize the way we develop software.