Node 22 is the new current!
Node Logo

Node 22 is the new current!

Node.js version 22 was released in April 2024. This is now the new current.

Roadmap

I finally found time to catch up on the latest version and review each update in detail. While the new V8 engine is fascinating and adds many new functions, it's not the most exciting aspect. This release includes new features that will significantly impact my daily workflow. I have also created a git repository highlighting each feature. Let's dive into the details.

Support require()ing synchronous ESM graphs

Previously, it was impossible to require modules or use mjs modules in Node.js. For example, if we create the file test.mjs:

export const test = function () {
  console.log("TEST");
};        

And then require it in another file, such as index.js:

const { test } = require("./test.mjs");
test();        

If you tried to run the previous code, you would have received this message:

Error ESM

With Node 22, it's now possible to run the following using the "--experimental-require-module" flag:

--experimental-require-module

The same applies to modules. Create a package.json file for a module:

{
  "type": "module",
  "name": "test",
  "version": "1.0.0",
  "main": "index.js"
}        

Then, in an index.js file located in the same folder as this package.json:

export const mtest = function () {
  console.log("TEST");
};        

You can now include this package as a dependency in your project and run it:

"module-test": "file:./module/module"        
const { mtest } = require("module-test");
mtest();        

Running package.json scripts

This is certainly the most impactful aspect of this release. I can't count the number of times I've run a script from a package.json. Instead of using the npm command:

npm run watch        

Now, you can run the scripts from the package.json using the following command with the --run flag:

node --run watch        

We can use Hyperfine, a command-line benchmarking tool, to compare the performance of both commands.

hyperfine test

The difference in performance between the two commands is quite remarkable. Using the node command is 5.7 times faster than using the npm command.

Stream default High Water Mark

The high water mark is a parameter that sets a limit on the amount of data that can be stored in the internal stream buffer. When this limit is reached, Node stops reading more data until the buffer is emptied. This mechanism helps limit memory usage and prevents your application from crashing. It's important to note that this limit acts as a threshold rather than a hard cap! This parameter can be tricky to manage. If set too low, the program may slow down significantly when executing lengthy processes that require a lot of information from a stream. If set too high, you risk crashing your application with a Java heap limit exception. The default value of stream has been increased by default from 16kiB to 64KiB.

Let's create a function inspired by examples found in the Node documentation. This function will read a very long text file in chunks using a stream:

const fs = require("node:fs");

async function print(readable, highWaterMark) {
  readable.setEncoding("utf8");
  let data = "";
  for await (const chunk of readable) {
    data += chunk;
  }
  console.log(
    `Everything has been read from the stream`
  );
}        

We will use the perf_hooks module to monitor performance and use getHeapStatistics to track memory heap usage.

async function print(readable, highWaterMark) {
  const start = performance.now();
  readable.setEncoding("utf8");
  let data = "";
  for await (const chunk of readable) {
    data += chunk;
  }
  const end = performance.now();
  const endMemory = getHeapStatistics().used_heap_size;
  console.log(
    `Everything has been read from the stream with ${highWaterMark} highWaterMark in ${
      end - start
    }ms with ${endMemory}`
  );
}        

We will run the function using both the previous default settings and the new version to compare their performance.

  // Previous default => 16 * 1024
  await print(
    fs.createReadStream(`${__dirname}/file.txt`, {
      highWaterMark: 16 * 1024,
    }),
    "16 * 1024"
  ).catch(console.error);

  // Default => 64 * 1024
  // With this value eveything is handle in one loop
  await print(
    fs.createReadStream(`${__dirname}/file.txt`, {
      highWaterMark: 64 * 1024,
    }),
    "64 * 1024"
  ).catch(console.error);        
Test High Water Mark

As we can see, the new high water mark limit speeds up the process, but it also obviously consumes more memory.

Watch Mode

Finally, hot refresh is now officially part of Node.js. Previously experimental, it has been officially released in this version. To use it, simply include the --watch flag:

node --watch index.js        

We will now officially say good bye to Nodemon.

Websocket Client

The new version of Node.js includes a built-in WebSocket client, eliminating the need for additional dependencies. To test this, we can create a WebSocket server server.js using the ws library:

const { WebSocketServer } = require("ws");

const wss = new WebSocketServer({ port: 8080 });

wss.on("connection", function connection(ws) {
  ws.on("message", function message(data) {
    console.log("received: %s", data);
  });

  ws.send("something");
});        

And we can connect directly using a Node.js script without any additional dependencies. For example, let's create a file named client.js:

const socket = new WebSocket("ws://localhost:8080");

socket.addEventListener("open", () => {
  socket.send("Hello Server!");
});        

We can run both scripts:

node client.js
node server.js        

You should see "Hello Server" in the console of server.js and "something" in the console of client.js.

test Websocket

Glob/GlobSync

Until now, I frequently used the npm package glob to list files in a directory according to a specific pattern. With this new release of Node, that dependency is no longer necessary. Glob and GlobSync have been implemented and can be imported from the fs module.

const { glob } = require("node:fs/promises");
const { globSync } = require("node:fs");

(async () => {
  for await (const entry of glob("**/*.js")) console.log(entry);
})();

console.log(globSync("**/*.js"));        

In the code above, I am listing all the JavaScript files within the project directory.

Improve performance of AbortSignal creation

For those unfamiliar with Node's AbortSignal API, this API allows you to interact with asynchronous operations. The performance of the AbortSignal with the fetch function has been improved in this release.

const mainFetchAborted = async () => {
  const resp = await fetch("https://localhost:3000", {
    signal: AbortSignal.timeout(2000),
  });
  const respBody = await resp.text();
  console.log(respBody);
};        

In the code above, if the call takes more than 2 seconds, it will time out and be aborted.

And that wraps up the highlights for Node.js 22!

Last Words

This release introduced many features that I now use almost daily. I'm now waiting October when this version reaches LTS status so I can use it in a production environment. I'm curious to see what Node 23 will bring. Let's wait and see!


要查看或添加评论,请登录

Kevin Justal的更多文章

  • NLP: Embedding Layer - Part II

    NLP: Embedding Layer - Part II

    Following my previous article, I will focus this time into a important component of Natural Language Processing (NLP):…

  • NLP: Summarization - Part I

    NLP: Summarization - Part I

    I recently did an interview where I encountered Spacy, a free open-source Python library for Natural Language…

  • Transactions with mongoose/mongodb

    Transactions with mongoose/mongodb

    Transactions, for those who might not be familiar, allow you to carry out multiple operations in isolation, with the…

  • Volta: extend the life of your project

    Volta: extend the life of your project

    How often have I launched a project only to discover that nothing works? How frequently have I navigated through a…

  • Did you say Scrum?

    Did you say Scrum?

    Agile, Agile, Agile..

  • Spline the new tool for amazing 3D effect

    Spline the new tool for amazing 3D effect

    I have a passion for creative development, particularly in the realms of WebGL, Three.js, and React-Three-Fiber.

  • The death of code golf with ChatGPT

    The death of code golf with ChatGPT

    Have you ever heard of code golf? It's a coder's game where the goal is to solve a problem with a minimum number of…

  • The A* search algorithm, the swiss knife of CodinGame

    The A* search algorithm, the swiss knife of CodinGame

    I love CodinGame. For those who does not know what it is about, I suggest you to try.

  • Circuit-Breaker, a nice pattern for microservices

    Circuit-Breaker, a nice pattern for microservices

    Patterns provide general solution, well documented and often proven to be helpful for making a piece of code robust and…

  • How to migrate a database from EC2 to DocumentDB on AWS?

    How to migrate a database from EC2 to DocumentDB on AWS?

    Recently, I got a very interesting task. In the name of high availability, I had to move a mongoDB database hosted on a…

社区洞察

其他会员也浏览了