DanLevy.net

Quiz: Dominio de IO en NodeJS

Pon a prueba tus conocimientos sobre archivos, flujos y buffers

¿Listo para sumergirte en el mundo del IO de NodeJS? 🌊

Este cuestionario pondrá a prueba tu comprensión de las operaciones de IO de Node, desde las tareas básicas del sistema de archivos hasta los conceptos avanzados de streaming. Cubriremos buffers, codificaciones y buenas prácticas para manejar datos de forma eficiente.

¡Veamos qué tan bien conoces tus streams frente a tus buffers! 🚀

¿Qué hace este código?

const buf = Buffer.alloc(5);
console.log(buf);

Buffer.alloc(size) crea un nuevo Buffer del tamaño especificado relleno de ceros. La salida será: <Buffer 00 00 00 00 00>

Si deseas crear un Buffer con datos aleatorios, usa Buffer.allocUnsafe(5).

Aprende más sobre la asignación de Buffer

¿Qué imprimirá esto?

const buf = Buffer.from([65]);
console.log(buf.toString());

Los números en el arreglo representan códigos ASCII:

  • 65: ‘A’

toString() convierte estos bytes a su representación en cadena usando codificación UTF-8 por defecto.

Aprende más sobre la codificación de Buffer

¿Cuál es el orden de salida?

import fs from 'fs';
fs.readFile('test.txt', 'utf8', (err, data) => {
console.log(data);
});
console.log('Done');

Como readFile es asíncrono, el código sigue ejecutándose mientras se lee el archivo. Por lo tanto, “Done” se imprimirá antes del contenido del archivo.

Para esperar a que el archivo se lea primero, podrías usar la versión basada en Promesas:

import { promises as fs } from 'fs';
async function read() {
const data = await fs.readFile('test.txt', 'utf8');
console.log(data);
console.log('Done');
}

¿Qué devuelve fs.readFileSync() por defecto?

import fs from 'fs';
const content = fs.readFileSync('test.txt');

fs.readFileSync() devuelve un Buffer por defecto cuando no se especifica una codificación. Si quieres una cadena, debes:

  1. Especificar una codificación: fs.readFileSync('test.txt', 'utf8')
  2. Convertir el Buffer: content.toString()

Aprende más sobre fs.readFileSync en la documentación de Node.js

¿Qué conjunto de eventos se usa comúnmente con los streams legibles?

Los streams legibles emiten varios eventos importantes:

  • ‘data’: Cuando hay datos disponibles para leer
  • ‘end’: Cuando no hay más datos que leer
  • ‘error’: Cuando ocurre un error
  • ‘close’: Cuando el stream y el recurso subyacente se han cerrado
const readable = fs.createReadStream('file.txt');
readable.on('data', chunk => console.log(chunk));
readable.on('end', () => console.log('Done!'));

Aprende más sobre los eventos de Stream

¿Qué hace este código?

import fs from 'fs';
const readable = fs.createReadStream('source.txt');
const writable = fs.createWriteStream('dest.txt');
readable.pipe(writable);

pipe() conecta un stream legible a un stream escribible, gestionando automáticamente la presión inversa y copiando los datos en fragmentos sin cargar todo el archivo en memoria.

Esto es eficiente en memoria para archivos grandes en comparación con fs.readFile() seguido de fs.writeFile().

Aprende más sobre pipe()

¿Qué hace la opción recursive?

import fs from 'fs';
fs.mkdirSync('./a/b/c', { recursive: true });

La opción recursive: true crea los directorios padre si no existen. Sin esta opción, intentar crear ’./a/b/c’ lanzaría un error si ’./a’ o ’./a/b’ no existen.

Es similar al comando de shell mkdir -p.

Aprende más sobre mkdir

¿Qué mostrará esto?

import { Transform } from 'stream';
const upperCase = new Transform({
transform(chunk, encoding, callback) {
callback(null, chunk.toString().toUpperCase());
}
});
process.stdin
.pipe(upperCase)
.pipe(process.stdout);
// Input: "hello world"

Los flujos de transformación modifican los datos mientras los atraviesan. Aquí, cada fragmento se:

  1. Convierte a una cadena
  2. Transforma a mayúsculas
  3. Se envía a stdout

Esto crea una canalización que convierte toda la entrada a mayúsculas.

Aprende más sobre los flujos Transform

¿Cuántas veces se garantiza que fs.watch() se dispare cuando se modifica un archivo?

import fs from 'fs';
fs.watch('test.txt', (eventType, filename) => {
console.log(`${filename} was changed`);
});
// Then modify test.txt once

fs.watch() no garantiza dispararse exactamente una vez por cada cambio lógico de archivo. A menudo se dispara varias veces porque muchos editores de texto:

  1. Guardan en un archivo temporal
  2. Lo renombran al archivo objetivo

Para una observación más fiable, considera usar:

  • El paquete chokidar
  • Aplicar debounce al callback
  • Usar fs.watchFile() (aunque es menos eficiente)

Aprende más sobre fs.watch()

¿Cuál es la salida?

const buf1 = Buffer.from('Hello');
const buf2 = Buffer.from('Hello');
console.log(buf1 === buf2);

Los buffers se comparan por referencia, no por valor. Aunque contengan los mismos datos, son objetos diferentes.

Para comparar el contenido de los buffers, use:

buf1.equals(buf2) // true
// or
Buffer.compare(buf1, buf2) === 0 // true

Aprende más sobre la comparación de Buffers

¿Cuál es el propósito principal del backpressure en streams?

El backpressure es un mecanismo que previene el desbordamiento de memoria pausando la lectura cuando el extremo de escritura no puede seguir el ritmo.

Ejemplo de backpressure manual:

readable.on('data', (chunk) => {
const canContinue = writable.write(chunk);
if (!canContinue) {
readable.pause();
writable.once('drain', () => readable.resume());
}
});

pipe() maneja esto automáticamente!

Aprende más sobre el backpressure

¿Qué hace este código?

import fs from 'fs';
fs.symlinkSync('target.txt', 'link.txt');

symlinkSync crea un enlace simbólico (como un acceso directo) al archivo objetivo.

Diferencias clave con los enlaces duros:

  • Puede enlazar a directorios
  • Puede abarcar sistemas de archivos
  • Se rompe si el objetivo se elimina

Para crear un enlace duro en su lugar:

fs.linkSync('target.txt', 'hardlink.txt');

Aprende más sobre los enlaces simbólicos

¿En qué modos pueden operar los streams de Node.js?

Los streams pueden operar en:

  1. Modo binario (por defecto): para buffers y cadenas
  2. Modo objeto: para cualquier valor de JavaScript

Ejemplo de modo objeto:

import { Transform } from 'stream';
const objectStream = new Transform({
objectMode: true,
transform(chunk, encoding, callback) {
callback(null, { value: chunk });
}
});

Aprende más sobre los modos de stream

¿Qué tipo es el parámetro fd en esta devolución de llamada?

import fs from 'fs';
fs.open('test.txt', 'r', (err, fd) => {
console.log(typeof fd);
});

Los descriptores de archivo son números que identifican de forma única los archivos abiertos en el sistema operativo.

Los tres primeros descriptores están reservados:

  • 0: stdin
  • 1: stdout
  • 2: stderr

Recuerda siempre cerrar los descriptores de archivo:

fs.close(fd, (err) => {
if (err) throw err;
});

Aprende más sobre los descriptores de archivo

¿Cuántos bytes ocupará esta cadena en UTF-8?

const str = "Hello 🌍";
const buf = Buffer.from(str);
console.log(buf.length);

En UTF-8:

  • Los caracteres ASCII (como ‘Hello ’) ocupan 1 byte cada uno
  • El emoji de la tierra 🌍 ocupa 4 bytes

Entonces: 5 (Hello) + 1 (espacio) + 4 (🌍) = 10 bytes

Para ver los bytes:

console.log(buf); // <Buffer 48 65 6c 6c 6f 20 f0 9f 8c 8d>

Aprende más sobre la codificación UTF-8

¡Espero que hayas disfrutado poniendo a prueba tus conocimientos de NodeJS IO! ¿Quieres más? Consulta mi Colección de quizzes para nuevos desafíos.