What’s new in Node.js 15?

We are sharing the translation of the article, which contains details about the new features of the 15th version of Node.js.

Version Node.js 15 was released on October 20, 2020. Major changes include:

  • throw mode on unhandled deviations
  • V8 8.6 language features
  • NPM 7
  • experimental QUIC support
  • N-API Version 7
  • finalization of the Async Local Storage API

Let’s take a closer look at what these innovations are and how they can be used.

Using NVM for Node Overview

IN previous article we have analyzed the instructions for use NVM (Node Version Manager) for Node.js and NPM version control. We have Node.js 12.16.0 and NPM 6.14.8 installed in our environment. By running nvm install node, we have installed Node.js 15.4.0 and NPM7.0.15.

We have two windows open, one with Node.js 12 and the other with Node.js 15.

In the window node12:

$ nvm use 12
Now using node v12.16.0 (npm v6.14.8)

In the window node15:

$ nvm use 15
Now using node v15.4.0 (npm v7.0.15)

We can now investigate this version.

Throw mode on unhandled promise rejection

Event unhandledRejection generated every time a promise is rejected and no error handler is attached to the promise during the event loop. As of Node.js 15, the default mode for unhandledRejection was changed from warn on throw… In mode throwif hook unhandledRejection not installed, unhandledRejection thrown as an exception not caught by the method catch

Create a program to rejected the promise with an error message:

function myPromise() {
  new Promise((_, reject) =>
    setTimeout(
      () =>
        reject({
          error: 'The call is rejected with an error',
        }),
      1000
    )
  ).then((data) => console.log(data.data));
}

myPromise();

When you run this code in a window node12, a long warning message appears:

$ node myPromise.js
(node:79104) UnhandledPromiseRejectionWarning: #<Object>
(node:79104) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)
(node:79104) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.Users that have an unhandledRejection hook should see no change in behavior, and it’s still possible to switch modes using the --unhandled-rejections=mode process flag.

When running this code in a window node15 an error is generated UnhandledPromiseRejection:

$ node myPromise.js
node:internal/process/promises:227
          triggerUncaughtException(err, true /* fromPromise */);
          ^[UnhandledPromiseRejection: This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). The promise rejected with the reason "#<Object>".] {
  code: 'ERR_UNHANDLED_REJECTION'
}

Add an error handler to the branch then in the code below (.catch ((error) => console.log (error.error)) also works).

function myPromise() {
  new Promise((_, reject) =>
    setTimeout(
      () =>
        reject({
          error: 'The call is rejected with an error',
        }),
      1000
    )
  ).then(
    (data) => console.log(data.data),
    (error) => console.log(error.error)
  );
}

myPromise();

Now the code runs correctly in both windows (node12 and node15):

$ node myPromise.js
The call is rejected with an error

It is recommended to write an error handler for promises. However, there may be cases where errors are not caught by the catch method. It is recommended to set up the unhandledRejection hook to detect potential errors.

function myPromise() {
  new Promise((_, reject) =>
    setTimeout(
      () =>
        reject({
          error: 'The call is rejected with an error',
        }),
      1000
    )
  ).then((data) => console.log(data.data));
}

myPromise();

process.on('unhandledRejection', (reason, promise) => {
  console.log('reason is', reason);
  console.log('promise is', promise);
  // Application specific logging, throwing an error, or other logic here
});

Hook unhandledRejection works in both Node.js 12 and Node.js 15. After installing it, unhandledRejection processed as needed.

$ node myPromise.js
reason is { error: 'The call is rejected with an error' }
promise is Promise { <rejected> { error: 'The call is rejected with an error' } }

V8 8.6 New language features

V8, JavaScript engine, updated from 8.4 to 8.6. version. In addition to various tweaks to improve performance, the new V8 has the following features:

  • Promise.any () and AggregateError (from V8 8.5)
  • await setTimeout and AbortController (experimental feature)
  • String.prototype.replaceAll () (from V8 8.5)
  • Logical assignment operators && =, || = and ?? = (from V8 8.5)

Promise.any () and AggregateError

First, let’s look at the existing method Promise.all ()

Promise.all () takes an iterable from promises as input and returns one promise, which is executed as an array of the results of the input promises.

The following program calls Promise.all () for two resolved promises:

function myPromise(delay) {
  return new Promise((resolve) =>
    setTimeout(
      () =>
        resolve({
          data: The data from ${delay} ms delay,
        }),
      delay
    )
  );
}

async function getData() {
  try {
    const data = await Promise.all([myPromise(5000), myPromise(100)]);
    console.log(data);
  } catch (error) {
    console.log(error);
  }
}

getData();

Promise.all () returns a promise that will be fulfilled when all input promises are resolved, or if the iterable contains no promises:

$ node myPromise.js
[
  { data: 'The data from 5000 ms delay' },
  { data: 'The data from 100 ms delay' }
]

The following program calls Promise.all () for two rejected promises.

function myPromise(delay) {
  return new Promise((_, reject) =>
    setTimeout(
      () =>
        reject({
          error: The error from ${delay} ms delay,
        }),
      delay
    )
  );
}

async function getData() {
  try {
    const data = await Promise.all([myPromise(5000), myPromise(100)]);
    console.log(data);
  } catch (error) {
    console.log(error);
  }
}

getData();

Promise.all () immediately rejects any rejection of the input promise or any error at the time of execution, and returns a message about this error:

$ node myPromise.js
{ error: 'The error from 100 ms delay' }

Promise.any () – new method in Node.js 15. It is the opposite of method Promise.all ()… Promise.any () accepts an iterable containing Promise objects. And, as soon as one of the Promises in the iterable succeeds, the method will return a single promise with the value of the fulfilled “promise”.

The following program calls Promise.any () for two resolved promises:

function myPromise(delay) {
  return new Promise((resolve) =>
    setTimeout(
      () =>
        resolve({
          data: The error from ${delay} ms delay,
        }),
      delay
    )
  );
}

async function getData() {
  try {
    const data = await Promise.any([myPromise(5000), myPromise(100)]);
    console.log(data);
  } catch (error) {
    console.log(error);
    console.log(error.errors);
  }
}

getData();

Promise.any () returns the first resolved promise:

$ node myPromise.js
{ data: 'The error from 100 ms delay' }

The following program calls Promise.any () for two rejected promises:

function myPromise(delay) {
  return new Promise((_, reject) =>
    setTimeout(
      () =>
        reject({
          error: The error from ${delay} ms delay,
        }),
      delay
    )
  );
}

async function getData() {
  try {
    const data = await Promise.any([myPromise(5000), myPromise(100)]);
    console.log(data);
  } catch (error) {
    console.log(error);
    console.log(error.errors);
  }
}

getData();

If the promises in the iterable fail, i.e. all promises given are rejected, the returned promise is rejected with AggregateError, a new subclass Errorwhich groups individual errors together.

$ node myPromise.js
[AggregateError: All promises were rejected]
[
  { error: 'The error from 5000 ms delay' },
  { error: 'The error from 100 ms delay' }
]

Await setTimeout and AbortController

In the previous examples, we used setTimeout inside a promise call.

SetTimeout in WindowOrWorkerGlobalScope, uses a callback. However timers / promises provide a promisified version setTimeoutwhich can be used with async / await.

const { setTimeout } = require('timers/promises');

async function myPromise(delay) {
  await setTimeout(delay);
  return new Promise((resolve) => {
    resolve({
      data: The data from ${delay} ms delay,
    });
  });
}

async function getData() {
  try {
    const data = await Promise.any([myPromise(5000), myPromise(100)]);
    console.log(data);
  } catch (error) {
    console.log(error);
    console.log(error.errors);
  }
}

getData();

AbortController Is a JavaScript object that allows one or more web requests to be interrupted at will. We have provided examples of use AbortController in another article about useAsync

AND await setTimeoutand AbortController are experimental features.

String.prototype.replaceAll ()

Let’s take a look at the existing method String.prototype.replace ()

replace () returns a new string with some or all of the pattern matches replaced with a placeholder. The pattern can be a string or a regular expression. The placeholder can be a string, or a function called for each match.

If the pattern is a string, only the first occurrence will be replaced.

'20+1+2+3'.replace('+', '-');

Using this operator will give “20-1 + 2 + 3”

To replace all “+” with “-“, you need to use a regular expression.

'20+1+2+3'.replace(/+/g, '-');

Using the above operator will give “20-1-2-3”

Method replaceAll () – new in Node.js 15. Thanks to its use, we don’t have to use a regular expression. This method returns a new string with all pattern matches replaced with the placeholder. The pattern can be a string or a regular expression, and the placeholder can be a string or a function called for each match.

Thanks to the method replaceAll (), we don’t need to use a regular expression to replace all “+” with “-“.

'20+1+2+3'.replaceAll('+', '-');

Execution of this operator gives “20-1-2-3”

Logical assignment operators && =, || = and ?? =

Logical assignment operator AND (x && = y) performs an assignment operation only if x is true.

x && = y equivalent to x && (x = y)but not equivalent x = x && y

let x = 0;
let y = 1;

x &&= 0; // 0
x &&= 1; // 0
y &&= 1; // 1
y &&= 0; // 0

OR logical assignment operator (x || = y) performs an assignment operation only if x is false.

x || = y equivalent to x || (x = y)but not equivalent x = x || at

let x = 0;
let y = 1;

x ||= 0; // 0
x ||= 1; // 1
y ||= 1; // 1
y ||= 0; // 1

Boolean assignment operator nullish (x ?? = y) performs an assignment operation only if x is NULL (null or undefined).

x ?? = y equivalent to x ?? (x = y), and is not equivalent x = x ?? at

let x = undefined;
let y = '';

x ??= null; // null
x ??= 'a value'; // "a value"
y ??= undefined; // ""
y ??= null; // ""

Other changes

Besides the regime throw with unhandled promise rejection and new V8 8.6 language features, Node.js 15 has the following changes:

NPM 7: Many changes, including automatic installation of peer-to-peer dependencies, improvements to packages and yarn.lock files, workspace support, and more. All this is described in this article on link

QUIC: Experimental support for UDP transport layer, which is the main protocol for HTTP / 3. QUIC includes built-in security with TLS 1.3, flow control, error correction, connection migration and multiplexing.

N-API Version 7: API for creating custom addons. It is independent of the underlying JavaScript runtime and is supported as part of Node.js.

Improvements to the Async Local Storage API: Provides the ability for more modern logging and feature analysis for large-scale applications.

Conclusion

The new version of Node.js 15 has a large number of new features and improvements, including quite significant ones.

Try the new version and get ready to update projects.

Thanks for attention! I hope the article was helpful to you.

Similar Posts

Leave a Reply