This Small Corner

Eric Koyanagi's tech blog. At least it's free!

NodeJS: History and Fundamentals

By Eric Koyanagi
Posted on

Let's talk about JavaScript

Back in the 1990s, web browsers were simple things. Some of us remember the static HTML sites of old. At that point, many people made websites by directly coding HTML. These were fun, naive times for the Internet that were not destined to last. In 1995, Netscape Navigator decided that websites should not be merely static.

For better or worse, they decided to implement a scripting language into their browser. They toyed with a few options -- one was to embed Sun's Java programming language, the other was hiring Brendan Eich (who would become the cofounder of the Mozilla project) to embed a language called "Scheme".

Netscape then decided that they wanted something new, more similar to Java as it was exploding in popularity. Indeed, the name "JavaScript" was a purposefully confusing marketing ploy by Netscape -- the original name was "LiveScript".

As some of us remember, Netscape Navigator's popularity was short-lived, with IE quickly reaching 95% market share by the early 2000s. Their version of "JS" (reversed engineered from Navigator) was called JScript. As you can imagine, Microsoft didn't much care for working with international standards in this context. They did their own thing because they controlled the market.

It wasn't until 2005 that this started to change. Firefox had just been released in 2004, eroding IE's absurdly dominant market position. They tried working with Macromedia to create a new standard, ECMAScript 4, but this was futile without Microsoft's adoption. Besides, it wasn't popular among developers, who thought it was just too "different" from established scripting modalities.

Other changes were happening outside the push for international standards. Jesse James Garrett released a white paper describing AJAX. This was huge, and sparked open source communities to release libraries like jQuery/Dojo/Prototype (I forgot that Dojo is a thing).

The final push to standardization happened in 2008 with the release of Chrome, which sported a JIT (just in time) compilation engine that was faster than its peers. In July of that year, these conflicting parties finally decided to combine their efforts and standardize -- this resulted in the ECMAScript 5 standard. This was further refined by ECMAScript 6 in 2015.

Now, about 98% of all websites use JavaScript -- and I'm personally surprised this percentage isn't higher, really.

Where NodeJS Fits

Node was created in 2009 by Ryan Dahl, not long after the release of chrome and the adoption of ECMA 5. Already, client side scripting was hugely important for the modern web experience. The idea of using JavaScript outside the browser is somewhat natural in this context. Why learn another backend language when an entire web stack can be coded in JS? If people think Python is used everywhere, its nothing compared to how universal JavaScript has become.

This, in a way, is similar to how "network effect" works in social media. Twitter was famously coded in a weekend, but replicating it won't lead to the same level of success because the "value" of a social network is its popularity, not its technology. The more devs that understand a language, the easier it is for firms to adopt. To the dismay of many engineers, technology choices aren't often about "what's best". Like a social network, there's inherent value in selecting a popular language, even if there might be something out there that's slightly faster.

That said, Node was impactful for more than its ability to unify a stack. With Apache being the most popular server back then, Dahl had a low opinion of its ability to handle concurrent connections. Since I/O is blocking, this made code very sequential and poorly suited for concurrent connections.

Node improved that bottleneck by offering non-blocking I/O through the use of callbacks, enabling code to "continue, but let us know the result later". This is no small improvement, greatly improving application throughput. I might write another article exploring some of the lower-level details of the event loop to explore exactly how this works, but there's so much granularity here we'll have to learn more about it later.

In general, when you tell a Node application to "await", you're saying "you're allowed to do other things until this is done". The event loop will handle resolving all waiting functions, but it's still able to handle connections as it does this because of this asynchronous model of application flow. You're giving the application permission to open the door for guests instead of waiting to finish your conversation. It's only polite.

The V8 Engine and Libuv

Under the hood, Node has two major part: the V8 engine, and Libuv. The general idea is that V8 handles running JavaScript code, while Libuv is responsible for low-level system operations like file management, OS operations, and concurrency. V8 is mostly C++ (with maybe 30% of it in JavaScript). Basically, JavaScript is just a "wrapper" for underlying code written in C or C++.

If you've used C or C++ before, you won't need much convincing for why using a higher-level language like JavaScript makes sense (compared to doing stuff directly in C/C++). Any performance gains you get from writing directly in lower level languages would likely be lost by the added headaches and dev working in a lower level.

How does Node Resolve Javascript to C++?

If you peak into Node functions (defined in /lib), you will eventually see references to the "internalBinding" method. This is a private, internal method used to load corresponding C++ implementations underlying the higher level JS code. This is how Node actually loads lower-level C++ code where we can interact with things like filesystems or the OS.

You are strongly discouraged from using this method to load your own C++ code, although if you're at the point where you are writing your own C++, you probably know what you're doing enough to make that choice yourself.

Basically, internalBinding works by mapping the name (passed as an argument) to a C++ internal binding that shares the same module name. Exactly how this is implemented depends on the version of Node, which is another reason you're strongly discouraged from using this method yourself.

Conclusion

Node erupted in 2009, shortly after Chrome and the ECMA5 standard came to be. It became popular because of its universality and the improved ability to handle concurrent I/O in a non-blocking way. Under the hood, it relies on a lower-level codebase in C++; like other backend languages (PHP), the higher-level language is backed by lower-level C/C++ implementations.

JavaScript was so named as a marketing ploy. It had a long road to universal adoption (thanks, Microsoft) and is still widely loathed by many developers who view it as...funky (and cry when reading about how JS handles "null"), but that shouldn't be a big surprise considering the history.

It's up to engineers to know why Node's non-blocking model is so good and utilize it to its fullest. It's very possible (and probably woefully common) to write synchronous code in Node. Knowing more about its history and the event loop, it's hopefully easier to fully understand why Node is so popular and how to start utilizing the non-blocking model.

« Back to Article List
Written By
Eric Koyanagi

I've been a software engineer for over 15 years, working in both startups and established companies in a range of industries from manufacturing to adtech to e-commerce. Although I love making software, I also enjoy playing video games (especially with my husband) and writing articles.

Article Home | My Portfolio | My LinkedIn
© All Rights Reserved