What is Node.js and how does it differ from a browser

Joao Santos
The Startup
Published in
6 min readAug 20, 2019

As a web developer, you will likely sooner or later be required to use node.js. Whether it is directly required as a server solution or if it’s required as a supporting tool for your web development it is a very good idea to know what node.js is, how it differs from running javascript in the browser and what exactly it can do.

The big picture

First and foremost, node.js is a javascript runtime based on chrome’s javascript engine called V8. In simple terms, people extracted the javascript engine from chrome and made it able to run standalone. But obviously it’s not that simple, there is no DOM, no UI, there are some runtime differences and we will go over the ones that affect your javascript or that are good to know

Getting started

To get started with node.js you have to download it from https://nodejs.org/en/

It supports all major OSes, which is a great thing because it means applications written for node.js run on all platforms. Note that you can lock yourself into a single OS in some situations when using native APIs that may not function the same or even exist in other OSes

Once installed, you will be able to start node.js with the command line, if started without arguments it will open in REPL mode where you can type javascript and it will be instantly evaluated, like in the console of a browser.

The more interesting use case is when you create a javascript file and launch node.js with the file path as your first argument. It will execute the javascript code inside.

The runtime behavior

Very much like javascript running in a browser, node.js is has a single thread for running javascript and it uses the event queue. Blocking the main thread does not freeze any UI but it is still bad practice because it prevents async tasks like web requests from ever being handled. Exceptions, flow, scoping all works identical to javascript modules. But there are many significant differences. Let’s go through the important ones

1. CommonJS

The first big thing you will notice is the way modules are loaded. Node.js has a module system that predates the modern import statement. While node.js has recently started supporting import, almost all code in the wild still uses common.js. In common.js you will use require to load a javascript module.

require(‘fs’)

Loads the node module ‘fs’ and returns the whole module export as an object. If the required module does not start with a / or . it will treat the import as an import for a node module as opposed to loading a file directly. The module resolution logic for node.js is a little unintuitive. Here are the rules:

  1. If the loaded module is a native module such as fs, crypto, path load the native module

2. If the loaded module is not a native module, go to the parent folder until you find a package.json. Once there, look if there is a folder called node modules, if yes, check if the module loaded is present there and load it if it is.

3. If module not found yet, keep going to the parent folder until you meet another package.json and repeat rule 2 until either module is found or root of the file system is reached, if it is reached without finding the module, throw an exception

This means if you have a nested project structure a project could (willingly or by accident) load the module from a parent project so watch out.

require(‘./test.js’)

This will load a file called test.js which must be in the same folder as the file requiring it. Luckily here the logic is simple. If the file isn’t where the path suggests it throws right here.

Require supports .js and .json extensions out of the box, but you can expand it to load any extension and it will run custom code to decide what to do with the string that contains all the file’s contents when importing.

When your file is imported through a require only the exported identifiers are available. To export something you need to assign it to exports

exports.test = 2

exports.something = function() { console.log(‘something };

A javascript file with those statements would expose an object containing properties test and something when imported as a module by another file in node.js

While a file is imported for the first time, the code inside the file will be evaluated and the exported values are kept in a cache so that if the file is imported again it won’t run the code again you will just get a reference to the cached export object. This might sound complicated but it’s actually quite intuitive (and exactly the same way as ES2015 modules work). If everything ran each time it was imported you would end up with many copies of the same things and a lot of wasted performance.

the require import is synchronous and blocking meaning the code after the require will not run until the entire import process is done

2. Full user-level system access.

This is one of the most exciting things about node.js. Unlike the browser where Javascript is sandboxed for your safety, node.js has full access to the system like any other native application. This means you can read and write directly to/from the file system, have unrestricted access to the network, can execute software and more. This means writing full desktop software is possible with node.js even including a UI through modules like electron. This means that javascript ran through node.js needs to be treated with the same level of caution as running C++, java, or any other language directly on your system. Never run untrusted javascript in node.js.

3. Global instead of Window

A lot of the APIs of the browser are missing like anything related to DOM and CSS, Performance, Document, APIs related to window. So for logic’s sake, the global object was renamed to global, since it does not refer to a window and has no window like properties

4. The Async IO threadpool

Browsers do have multiple threads to support the execution of javascript but in node.js the threadpool is used for super fast IO. When you use native modules they can tap into the threadpool, usually to do things like read from disk or send/receive data over the network in the background without wasting precious main thread CPU cycles that are reserved to your javascript code. This means that as long as you use the async versions of IO operation methods, the IO is basically zero cost for the javascript thread because the load is handled by another thread in the background. This is part of what makes it possible to have high-performance javascript based servers even though javascript itself only runs on one thread.

What can you do with node.js

Node.js is primarily used to make web servers and CLI tools, however, node.js can do so much more. It can do pretty much anything you could do with a native application. AAA Games? Use the Vulkan API (https://github.com/maierfelix/nv) to create a window and create your game. The indie game Cross Code runs on node.js through nwjs, an electron competitor. PC applications? Slack and Geforce experience is done with node.js through electron (https://electronjs.org/). Even a whole IDE can be done, vscode was made in node.js through electron and it performs great. The typescript compiler runs in node.js. Npm runs in node.js. You can even extend what node.js can do using C++ if the library for what you want does not yet exist. With node.js almost everything you can want is just a few npm installs away.

What’s the point of all this?

Sure, there are technologies already in place that can do all that node.js can do and more. But there is one major reason why node.js exists and why it is so popular. That reason is: It runs javascript like we are used to. It’s that simple. It allows all the javascript fans to use their favorite language not only in the browser but across the full stack. It reduces how much you have to learn to achieve something across the whole stack and it even allows sharing of code between back and front end. The whole serverless concept couldn’t have been born without this fact.

So next time you as a web developer aspire to do something beyond the browser, node.js will be there to empower you, without demanding for you to learn a whole new language and ecosystem.

Thank you for reading my post, if you liked it please remember to clap and put your criticism in the comments so I can improve.

--

--

Joao Santos
The Startup

Webdeveloper, interviewer and author of Aurum.js