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.
- 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.\ - 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