E Tech.

See Node.js API - 2

Overview

Next to See Node.js API! I pick up some documentation that caught my attention because there are so many interesting modules.

APIs

node:console

I've often used console.log in Node.js without thinking much about the difference between browser version and Node.js version. In Node.js, we can create a simple logger, and the output isn't limited to just stdout.
Reference : Class: Console

import { createWriteStream } from 'node:fs';
import { Console } from 'node:console';
// Alternatively
// const { Console } = console;

const output = createWriteStream('./stdout.log');
const errorOutput = createWriteStream('./stderr.log');
// Custom simple logger
const logger = new Console({ stdout: output, stderr: errorOutput });
// use it like console
const count = 5;
logger.log('count: %d', count);
// In stdout.log: count 5

Additionally, the global console in Node.js is just a special instance of:

new Console({ stdout: process.stdout, stderr: process.stderr });

node:diagnostics_channel

This module creates channels for diagnostic messages. To access a channel, you only need to know its name. The official documentation does not recommend using this module in production because of additional runtime overhead. It's intended for diagnostics—not for logging.
Reference : Diagnostics Channel

import diagnostics_channel from 'node:diagnostics_channel';

// Get a reusable channel object
const channel = diagnostics_channel.channel('my-channel');

function onMessage(message, name) {
  // Received data
}

// Subscribe to the channel
diagnostics_channel.subscribe('my-channel', onMessage);

// Check if the channel has an active subscriber
if (channel.hasSubscribers) {
  // Publish data to the channel
  channel.publish({
    some: 'data',
  });
}

// Unsubscribe from the channel
diagnostics_channel.unsubscribe('my-channel', onMessage);

node:dns

This module offers two ways to resolve DNS names. The first is dns.lookup(), which appears asynchronous in JavaScript, but is implemented synchronously under the hood. The second is dns.resolve(), which is fully asynchronous and generally more performance-friendly.

import dns from 'node:dns';

dns.lookup('example.org', (err, address, family) => {
  console.log('address: %j family: IPv%s', address, family);
});
// address: "2606:2800:21f:cb07:6820:80da:af6b:8b2c" family: IPv6

Reference : implementation-considerations

Error Class

There are multiple ways to handle and propagate errors in Node.js.

  1. Synchronous APIs
    These APIs neither return a Promise nor accept a callback. They throw JavaScript errors that must be caught; otherwise, Node.js will exit immediately.\
  2. Asynchronous APIs
    This includes several approaches to error handling.
    ■Rejected Promise:
const fs = require('node:fs/promises');

(async () => {
  let data;
  try {
    data = await fs.readFile('a file that does not exist');
  } catch (err) {
    console.error('There was an error reading the file!', err);
    return;
  }
  // Otherwise handle the data
})();

■Callback-based:

const fs = require('node:fs');
fs.readFile('a file that does not exist', (err, data) => {
  if (err) {
    console.error('There was an error reading the file!', err);
    return;
  }
  // Otherwise handle the data
});

■EventEmitter-based:
In this case, try...catch won't catch the error, since the error event is emitted asynchronously.

const net = require('node:net');
const connection = net.connect('localhost');

// Adding an 'error' event handler to a stream:
connection.on('error', (err) => {
  // If the connection is reset by the server, or if it can't
  // connect at all, or on any sort of error encountered by
  // the connection, the error will be sent here.
  console.error(err);
});

connection.pipe(process.stdout);

Make sure to use the appropriate error-handling pattern for each API.

Reference : Error propagation and interception

node:events

The EventEmitter calls all listeners synchronously in the order in which they were registered. However, if you use setImmediate, the listener executes asynchronously. See the output of following code.

import { EventEmitter } from 'node:events';
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter();
myEmitter.on('event', (a, b) => {
setImmediate(()=>{
    console.log('this happens asynchronously 1');
})
console.log('this happens synchronously 1');
});
myEmitter.emit('event', 'a', 'b');

//output
// this happens synchronously 1
// this happens asynchronously 1

Reference : Asynchronous vs. synchronous