Node.js o Node tiene un pequeño grupo central de módulos, comúnmente conocido como Node Core que se expone como la API pública de Node cuando escribimos nuestras aplicaciones o podemos decir que Node Core implementa la API pública de Node.
Algunos ejemplos de los módulos presentes en el núcleo del Node son:
- Para trabajar con sistemas de archivos tenemos un módulo fs .
- Para redes, tenemos un módulo http .
- Para obtener información específica del sistema operativo, tenemos un módulo llamado os .
Como estos, hay docenas de módulos en el núcleo del Node, pero la mayoría de ellos están ahí para admitir el caso de uso principal del Node. Node maneja sus operaciones de E/S principalmente con devoluciones de llamada , eventos y flujos . Entonces necesitas entender estos conceptos.
Antes de comenzar a hablar sobre los conceptos mencionados anteriormente, asegúrese de haber instalado node.js. Si tiene problemas para instalarlo, puede consultar nuestra guía de instalación .
Devoluciones de llamada: las devoluciones de llamada son uno de los fundamentos más importantes que debe comprender para dominar Node. Antes de eso, veamos por qué necesitamos devoluciones de llamada y cómo funcionan las devoluciones de llamada en Node.
Los servidores web tradicionales funcionan sincrónicamente . Significa que cuando se envía una solicitud al servidor, el servidor procesa la solicitud y entrega la respuesta. En el período de procesamiento, otras operaciones de E/S deben esperar a que finalice el proceso actual, luego solo se puede procesar otra solicitud. A esto lo llamamos E/S de bloqueo ya que la nueva solicitud se bloquea hasta que finaliza el proceso actual.
El Node tiene un modelo de E/S sin bloqueo porque el Node tiene un diseño asíncrono . Servidores hechos con Node cuando recibe una solicitud, la procesa y devuelve la respuesta como servidores tradicionales. Pero el servidor Node puede realizar otras tareas simultáneamente cuando la solicitud se encuentra en el período de procesamiento.
Ejemplo: Cree una nueva carpeta, luego cree un archivo learn-callback.js y un archivo name.txt dentro de él. Nuestro objetivo es imprimir un saludo personalizado y un patrón de bucle en la terminal. Pon tu nombre en nombre.txt y guarda el archivo. Tenemos » GeeksforGeeks » en nuestro archivo.
- Versión síncrona del servidor tradicional:
// Tell node we need to work with filesystem
const fs = require(
"fs"
);
// Read the file contents "synchronously" in
// string (utf-8) encoding
const fileContents = fs.readFileSync(
"name.txt"
,
"utf-8"
);
// Print to console
console.log(
"Hello, "
, fileContents);
// Print pattern
for
(let i = 0; i < 5; i++) console.log(i);
Producción:
Hello, GeeksforGeeks 0 1 2 3 4
- La versión asíncrona de Node: abre tu terminal en el directorio donde se guardan tus archivos. Ejecute el código usando el Node learn-callback.js y observe el resultado. llegará al punto, pero primero, vea la versión Node.
// Tell node we need to work with filesystem
const fs = require(
"fs"
);
// Read the file contents "asynchronously" in
// string (utf-8) encoding
fs.readFile(
"name.txt"
,
"utf-8"
, (error, fileContents) => {
if
(error)
return
error;
else
console.log(
"Hello, "
, fileContents);
});
// Print the pattern
for
(let i = 0; i < 5; i++)
console.log(i);
Producción:
0 1 2 3 4 Hello, GeeksforGeeks
Explicación: ejecute el código mediante el Node learn-callback.js . ¿Notas alguna diferencia en las salidas? Se debe al modelo sin bloqueo de Node. En la versión síncrona , primero observamos hola, luego el patrón. Enviamos una solicitud para leer el archivo name.txt , el archivo se procesa, se imprime hola y luego se imprime el patrón. En el modelo síncrono , la ejecución es secuencial, es decir, en orden de arriba a abajo.
En la versión asíncrona del Node , cuando activamos una solicitud para leer el archivo, el archivo comienza a procesarse, pero en este caso, nuestro programa puede realizar otras tareas simultáneamente mientras el Node lee el archivo. Esto ahorra recursos informáticos y hace que las operaciones de E/S de Node sean extremadamente rápidas.
En el código resaltado anteriormente, fs.readFile le dice al Node que lea el archivo name.txt en codificación utf-8. El tercer argumento de fs.readFile es una devolución de llamada. Las devoluciones de llamada son funciones que se ejecutan cuando finaliza un proceso en particular. Cuando se lee el archivo, el Node está libre y ejecuta la siguiente línea de código justo después de la función fs.readFile , que resulta ser un bucle en nuestro caso, por lo que el bucle se ejecuta durante el proceso de lectura y obtenemos un patrón en el Terminal. Cuando finaliza la lectura, se ejecuta la función de devolución de llamada y se imprime hola en la terminal después del patrón.
Entonces, las devoluciones de llamada son funciones que se ejecutan más tarde en el tiempo después de que un proceso ha terminado de ejecutarse y en ese período el Node está libre para realizar otras tareas. Tenga en cuenta que las devoluciones de llamada no son una característica especial de un Node. En realidad, están integrados en JavaScript. Node simplemente lo usa de manera inteligente para lograr la naturaleza de E/S sin bloqueo.
Eventos: puedes pensar en eventos como ‘cuando X le sucede a Y’. Entonces, en esta analogía, ‘X’ es un evento emitido por Node e ‘Y’ es un oyente que espera que la señal ‘X’ haga su trabajo. Escribamos un pequeño programa para captar este concepto.
- Ejemplo: Este ejemplo ilustra los Eventos. Ejecute este código y vea si obtiene el resultado correcto.
// Require "events"; give us access to EventEmitter class
// EventEmitter class has all the event related methods in it
const EventEmitter = require(
"events"
);
// Create an instance of the EventEmitter class
const ourEmitter =
new
EventEmitter();
// Create an event listener - listens for the "GfG opened" event
// Event listeners always keep its ear open; it never sleeps
// Means it'll keep on listening for the event throughout the code
// It'll execute the callback function when "GfG opened" event is emitted
ourEmitter.on(
"GfG opened"
, (error) => {
if
(error)
return
error;
else
console.log(
"Let's learn computer science concepts."
);
});
// Emit event or send a signal that "GfG opened" has happened
ourEmitter.emit(
"GfG opened"
);
Producción:
Let's learn computer science concepts.
- Programa donde poner ourEmitter.emit(“GfG abierto”); antes del detector de eventos:
...
// Emit "GfG opened"
ourEmitter.emit(
"GfG opened"
);
// Create an event listener
ourEmitter.on(
"GfG opened"
, (error) => {
if
(error)
return
error;
else
console.log(
"Let's learn computer science concepts."
);
...
Salida: la API de eventos del Node dice:
"When the EventEmitter object emits an event, all of the functions attached to that specific event are called synchronously"
Explicación: cuando emite el evento «GfG abierto», tenemos un detector de eventos que ejecuta la función de devolución de llamada que imprime un mensaje en la consola. Ahora veamos qué pasa cuando ponemos ourEmitter.emit(“GfG open”); antes del detector de eventos.
Significa que cuando el Node emite el evento «GfG abierto», el Node verifica si hay alguien escuchando este evento, pero el Node aún no conoce al oyente, ya que el oyente está detrás del comando de emisión. El comando de evento de Node .emit
no puede verificar los oyentes que aparecen después del comando de emisión porque es sincrónico . Entonces, el orden del código es importante cuando se trata de eventos. La regla de oro es: primero escucha y luego emite. Primero, cree un oyente y luego emita el evento.
Los eventos son útiles para crear servidores de juegos que necesitan saber cuándo se conectan o desconectan nuevos jugadores, se mueven, disparan, mueren, etc. Además, los eventos se usan mucho para crear salas de chat en las que desea transmitir mensajes a los oyentes.
Secuencias: la lectura y escritura de datos tiene dos enfoques: Buffered y Streams . En el enfoque almacenado en búfer, todos los datos deben leerse antes de que pueda comenzar el proceso de escritura. Pero las corrientes son mucho más eficientes. Los flujos leen un fragmento de datos, en ese momento otro flujo puede seguir escribiendo el fragmento de datos anterior. Entonces, node.js maneja los datos de forma asincrónica, haciendo tareas en paralelo .
Los arroyos vienen con tubería. Básicamente, lo que hace la tubería es que toman la salida de una secuencia y esa salida se puede enviar a otra secuencia a través de la tubería que se convierte en entrada para esa nueva secuencia. Esto le da poderes asombrosos al Node. Las secuencias son eficientes en el tiempo porque no están perdiendo el tiempo esperando que suceda toda la lectura a la vez, sino que estamos constantemente leyendo y escribiendo al mismo tiempo. Sí, lo estamos haciendo de forma asíncrona como dicen.
Además, los flujos son espacialmente eficientes (ahorran espacio en la memoria). Supongamos que tenemos que leer un archivo de 100 MB y escribirlo en alguna parte, y tenemos un búfer de 50 MB. El enfoque almacenado en búfer primero necesita leer todos los datos y luego puede comenzar a escribirlos. Con el enfoque de almacenamiento en búfer cuando comienza el proceso de lectura, nuestro búfer eventualmente se filtrará tan pronto como superemos la marca de 50 MB.
Pero podemos usar secuencias para leer fragmentos de datos de 50 MB, escribir esos datos y luego borrar ese búfer antes de continuar para leer los siguientes 50 MB. Entonces no habrá fugas en el caso de stream.
Publicación traducida automáticamente
Artículo escrito por vivekmittalagrawal y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA