Node.js has been released on schedule as per its yearly release cycle and as always there are ton of improvements. We will cover the notable improvements and features to the javascript runtime.

Node.js not only ships core features with new releases but also releases the optimisations delivered with Chrome's V8 engine.

Diagnostic Reports are Stable 🔖

Diagnostic reports were added as experimental features in Node 12 but this version marks them as stable. These reports are structured JSON formatted outputs generated by Node. You can mark these reports to be generated on specific events like crashes or ask Node environment to generate them on-demand.

Here is how you can use them. Run your Node process with following command:

node --report-uncaught-exception --report-on-signal \
--report-on-fatalerror app.js
  • --report-uncaught-exception Enables report to be generated on un-caught exceptions. Useful when inspecting JavaScript stack in conjunction with native stack and other runtime environment data.
  • --report-on-signal Enables report to be generated upon receiving the specified (or predefined) signal to the running Node.js process. (See below on how to modify the signal that triggers the report.) Default signal is SIGUSR2.

In fact those reports can also be written via Javascript from inside the process.

process.report.writeReport('./foo.json');

You can see the full documentation about them on Node,js Documentation page.

V8 Runtime Upgraded to 8.1 💫

Node 12.16 shipped with V8 version 7.8. There have been many improvements to V8 runtime after that release. Here are the improvements which are coming to Node 14 as a result of V8 upgrade.

Performance and Speed ⏱

OCR Caching brings upto 18% improvement in execution time.

Builtin functions are upto 12% faster due to new API which allows them to go through C++ Runtime

Double ⇒ Tagged transitions deprecation brings upto 12% improvements in speed.

Pointer compression brings upto 40% heap size reduction. This improvement is also combined with garbage collector and speed improvements of upto 10%.

Turbofan can now optimise higher order builtin functions like charAt , Array.prototype.map , Function.prototype.apply and many more. This means that if your code uses these functions, they will automatically be more optimised.

These updates to core engine is definitely bound to make the Node.js codes run faster and use lesser memory. Our personal favourite is the Pointer Compression.

Optional Chaining ⛓

We wrote codes like this before:

// Error prone-version, could throw.
const nameLength = db.user.name.length;

// Less error-prone, but harder to read.
let nameLength;
if (db && db.user && db.user.name)  
  nameLength = db.user.name.length;

Now, it's also possible to write the above code like this:

// Still checks for errors and is much more readable.
const nameLength = db?.user?.name?.length;

Nullish Coalescing ❓❓

The nullish coalescing operator ?? is a new short-circuiting binary operator for handling default values. Currently, default values are sometimes handled with the logical || operator, such as in the following example.

function Component(props) {  
  const enable = props.enabled || true;  
  // …
}

Use of || is undesirable for computing default values because a || b evaluates to b when a is falsy. If props.enabled were explicitly set to false, enable would still be true. With the nullish coalescing operator, a ?? b evaluates to b when a is nullish (null or undefined), and otherwise evaluates to a.

function Component(props) {  
  const enable = props.enabled ?? true;  
  // …
}

Intl.DisplayNames 🉑

The new Intl.DisplayNames API lets programmers display translated names of languages, regions, scripts, and currencies with ease.

const zhLanguageNames = new Intl.DisplayNames(['zh-Hant'], { type: 'language' });
const enRegionNames = new Intl.DisplayNames(['en'], { type: 'region' });
const itScriptNames = new Intl.DisplayNames(['it'], { type: 'script' });
const deCurrencyNames = new Intl.DisplayNames(['de'], {type: 'currency'});

zhLanguageNames.of('fr');
// → '法文'
enRegionNames.of('US');
// → 'United States'
itScriptNames.of('Latn');
// → 'latino'
deCurrencyNames.of('JPY');
// → 'Japanischer Yen'

Local Storage API (Experimental) 💿

This class is used to create asynchronous state within callbacks and promise chains. It allows storing data throughout the lifetime of a web request or any other asynchronous duration. It is similar to thread-local storage in other languages.

This is just introduced in this version so no frameworks support it, but due to its usefulness, we believe this will be utilised by web frameworks like Express and Fastify.

You can read about how it works on Async Hooks page.

WASI (Experimental) ✍️

Packages written in Web Assembly for Node.js bring the opportunity for better performance and cross-platform support for certain use cases. The 14.x release includes an experimental implementation of the Web Assembly System Interface (WASI) in order to help support these use cases.

You can read more about it in the API docs: https://nodejs.org/api/wasi.html.

Other Notable Changes ⚙️

  • Streams API has got major SemVer change. There are lot of changes under the hood. A notable change is that the `autoDestroy` option is now defaulted to true, making the stream always call `_destroy` after ending.
  • Usage of ESM modules don't require — experimental-modules flag and they don't show a warning that ESM modules are experimental.
  • Minimum MacOS version requires is 10.13. Node.js packages are also notarised on MacOS. Node binaries for Linux are still built with GCC 6 but in future they will be built with GCC 8. Node.js 14 will not work on End-of-life windows versions.

Conclusion ✅

The Node team always strives to improve the runtime and they did a great job in last year as well. We at Gumlet make heavy use of Node.js in our technology stack and we are super excited to try the new features.

You can read full post done by Node team in this official release article. If you are a nerd like me, you can also go through full CHANGELOG found on Github.