¿Qué es Node.js? Explicación del tiempo de ejecución de JavaScript

La escalabilidad, la latencia y el rendimiento son indicadores clave de rendimiento para los servidores web. Mantener la latencia baja y el rendimiento alto mientras se escala hacia arriba y hacia afuera no es fácil. Node.js es un entorno de ejecución de JavaScript que logra una baja latencia y un alto rendimiento al adoptar un enfoque "sin bloqueo" para atender las solicitudes. En otras palabras, Node.js no pierde tiempo ni recursos esperando que regresen las solicitudes de E / S.

En el enfoque tradicional para crear servidores web, para cada solicitud o conexión entrante, el servidor genera un nuevo hilo de ejecución o incluso bifurca un nuevo proceso para manejar la solicitud y enviar una respuesta. Conceptualmente, esto tiene mucho sentido, pero en la práctica genera una gran cantidad de gastos generales.

Si bien la generación de subprocesos implica menos memoria y sobrecarga de CPU que los procesos de bifurcación , aún puede ser ineficiente. La presencia de una gran cantidad de subprocesos puede hacer que un sistema muy cargado gaste ciclos preciosos en la programación de subprocesos y el cambio de contexto, lo que agrega latencia e impone límites en la escalabilidad y el rendimiento.

Node.js adopta un enfoque diferente. Ejecuta un bucle de eventos de un solo subproceso registrado con el sistema para manejar las conexiones, y cada nueva conexión hace que se active una función de devolución de llamada de JavaScript . La función de devolución de llamada puede manejar solicitudes con llamadas de E / S sin bloqueo y, si es necesario, puede generar subprocesos de un grupo para ejecutar operaciones de bloqueo o de uso intensivo de la CPU y equilibrar la carga entre los núcleos de la CPU. El enfoque de Node para escalar con funciones de devolución de llamada requiere menos memoria para manejar más conexiones que la mayoría de las arquitecturas competitivas que escalan con subprocesos, incluido el servidor HTTP Apache, los diversos servidores de aplicaciones Java, IIS y ASP.NET y Ruby on Rails.

Node.js resulta ser bastante útil para aplicaciones de escritorio además de servidores. También tenga en cuenta que las aplicaciones de nodo no se limitan a JavaScript puro. Puede utilizar cualquier lenguaje que se transpile a JavaScript, por ejemplo, TypeScript y CoffeeScript. Node.js incorpora el motor JavaScript Google Chrome V8, que admite la sintaxis ECMAScript 2015 (ES6) sin necesidad de un transpilador ES6 a ES5 como Babel.

Gran parte de la utilidad de Node proviene de su gran biblioteca de paquetes, a la que se puede acceder desde el npmcomando. NPM, el administrador de paquetes de Node, es parte de la instalación estándar de Node.js, aunque tiene su propio sitio web.

Algo de historia de JavaScript

En 1995, Brendan Eich, entonces contratista de Netscape, creó el lenguaje JavaScript para ejecutarlo en los navegadores web, en 10 días, según cuenta la historia. Inicialmente, JavaScript estaba destinado a permitir animaciones y otras manipulaciones del modelo de objetos de documento (DOM) del navegador. Poco después se introdujo una versión de JavaScript para Netscape Enterprise Server.

El nombre JavaScript se eligió con fines de marketing, ya que el lenguaje Java de Sun fue ampliamente publicitado en ese momento. De hecho, el lenguaje JavaScript se basó principalmente en los lenguajes Scheme y Self, con una semántica superficial similar a Java.

Inicialmente, muchos programadores descartaron JavaScript como inútil para el "trabajo real" porque su intérprete corrió un orden de magnitud más lento que los lenguajes compilados. Eso cambió a medida que varios esfuerzos de investigación destinados a hacer JavaScript más rápido comenzaron a dar sus frutos. Lo más destacado es que el motor de código abierto Google Chrome V8 JavaScript, que realiza compilación, alineación y optimización de código dinámico justo a tiempo, en realidad puede superar al código C ++ para algunas cargas y a Python en la mayoría de los casos de uso.

La plataforma Node.js basada en JavaScript fue introducida en 2009, por Ryan Dahl, para Linux y MacOS, como una alternativa más escalable al servidor HTTP Apache. NPM, escrito por Isaac Schlueter, se lanzó en 2010. Una versión nativa de Windows de Node.js debutó en 2011.

Joyent fue propietario, gobernó y apoyó el esfuerzo de desarrollo de Node.js durante muchos años. En 2015, el proyecto Node.js se entregó a la Fundación Node.js y pasó a ser gobernado por el comité directivo técnico de la fundación. Node.js también se adoptó como un proyecto colaborativo de la Fundación Linux. En 2019, la Fundación Node.js y la Fundación JS se fusionaron para formar la Fundación OpenJS.

Arquitectura básica de Node.js

En un nivel alto, Node.js combina el motor JavaScript de Google V8, un bucle de eventos sin bloqueo de un solo subproceso y una API de E / S de bajo nivel. El código de ejemplo simplificado que se muestra a continuación ilustra el patrón de servidor HTTP básico, utilizando funciones de flecha ES6 (funciones Lambda anónimas declaradas mediante el operador de flecha gruesa =>) para las devoluciones de llamada.

El comienzo del código carga el módulo HTTP, establece la hostnamevariable del servidor en localhost(127.0.0.1) y establece la portvariable en 3000. Luego crea un servidor y una función de devolución de llamada, en este caso una función de flecha gruesa que siempre devuelve lo mismo. respuesta a cualquier solicitud: statusCode200 (éxito), tipo de contenido texto sin formato y una respuesta de texto de ”Hello World\n”. Finalmente, le dice al servidor que escuche en el localhostpuerto 3000 (a través de un socket) y define una devolución de llamada para imprimir un mensaje de registro en la consola cuando el servidor ha comenzado a escuchar. Si ejecuta este código en una terminal o consola usando el nodecomando y luego navega a localhost: 3000 usando cualquier navegador web en la misma máquina, verá "Hello World" en su navegador. Para detener el servidor, presione Control-C en la ventana del terminal.

Tenga en cuenta que cada llamada realizada en este ejemplo es asincrónica y sin bloqueo. Las funciones de devolución de llamada se invocan en respuesta a eventos. La createServerdevolución de llamada maneja un evento de solicitud de cliente y devuelve una respuesta. La listendevolución de llamada maneja el listeningevento.

La biblioteca de Node.js

Como puede ver en el lado izquierdo de la figura a continuación, Node.js tiene una amplia gama de funcionalidades en su biblioteca. El módulo HTTP que usamos en el código de muestra anterior contiene clases de cliente y servidor, como puede ver en el lado derecho de la figura. La funcionalidad del servidor HTTPS que usa TLS o SSL vive en un módulo separado.

Un problema inherente con un bucle de eventos de un solo subproceso es la falta de escala vertical, ya que el subproceso del bucle de eventos solo utilizará un único núcleo de CPU. Mientras tanto, los chips de CPU modernos a menudo exponen ocho o más núcleos, y los racks de servidores modernos a menudo tienen varios chips de CPU. Una aplicación de un solo subproceso no aprovechará al máximo los más de 24 núcleos en un robusto rack de servidores.

Puede solucionarlo, aunque requiere algo de programación adicional. Para empezar, Node.js puede generar procesos secundarios y mantener conductos entre el padre y los secundarios, de manera similar a como funciona la popen(3)llamada al sistema , usando child_process.spawn() métodos relacionados.

El módulo de clúster es incluso más interesante que el módulo de proceso hijo para crear servidores escalables. El cluster.fork()método genera procesos de trabajo que comparten los puertos del servidor de los padres, usando child_process.spawn()debajo de las cubiertas. El clúster maestro distribuye las conexiones entrantes entre sus trabajadores utilizando, de forma predeterminada, un algoritmo de operación por turnos que es sensible a las cargas de los procesos de los trabajadores.

Tenga en cuenta que Node.js no proporciona lógica de enrutamiento. Si desea mantener el estado de las conexiones en un clúster, deberá mantener su sesión y los objetos de inicio de sesión en algún lugar que no sea la RAM de trabajo.

El ecosistema de paquetes de Node.js

El registro de NPM aloja más de 1.2 millones de paquetes de código Node.js reutilizable y gratuito, lo que lo convierte en el registro de software más grande del mundo. Tenga en cuenta que la mayoría de los paquetes de NPM (esencialmente carpetas o elementos de registro de NPM que contienen un programa descrito por un archivo package.json) contienen varios módulos (programas que carga con requiredeclaraciones). Es fácil confundir los dos términos, pero en este contexto tienen significados específicos y no deben intercambiarse.

NPM puede administrar paquetes que son dependencias locales de un proyecto en particular, así como herramientas JavaScript instaladas globalmente. Cuando se usa como administrador de dependencias para un proyecto local, NPM puede instalar, en un comando, todas las dependencias de un proyecto a través del archivo package.json. Cuando se utiliza para instalaciones globales, NPM a menudo requiere privilegios de sistema (sudo).

Usted no tiene que utilizar la línea de comandos NPM para acceder al registro de la NGP pública. Otros administradores de paquetes, como Yarn de Facebook, ofrecen experiencias alternativas del lado del cliente. También puede buscar y explorar paquetes utilizando el sitio web de NPM.

¿Por qué querrías usar un paquete NPM? En muchos casos, instalar un paquete a través de la línea de comandos de NPM es lo más rápido y conveniente para que la última versión estable de un módulo se ejecute en su entorno y, por lo general, es menos trabajo que clonar el repositorio de origen y crear una instalación desde el repositorio. Si no desea la última versión, puede especificar un número de versión para NPM, lo que es especialmente útil cuando un paquete depende de otro paquete y podría romperse con una versión más nueva de la dependencia.

Por ejemplo, el marco Express, un marco de aplicación web Node.js mínimo y flexible, proporciona un conjunto sólido de características para crear aplicaciones web híbridas y de una o varias páginas. Si bien el repositorio de Expresscode, que se puede clonar fácilmente, se encuentra en //github.com/expressjs/express y la documentación de Express está en //expressjs.com/, una forma rápida de comenzar a usar Express es instalarlo en un desarrollo de trabajo local ya inicializado. directorio con el npmcomando, por ejemplo:

$ npm install express —save

La —saveopción, que en realidad está activada de forma predeterminada en NPM 5.0 y versiones posteriores, le dice al administrador de paquetes que agregue el módulo Express a la lista de dependencias en el archivo package.json después de la instalación.

Otra forma rápida de comenzar a usar Express es instalar el generador ejecutable express(1) globalmente y luego usarlo para crear la aplicación localmente en una nueva carpeta de trabajo:

$ npm instalar -g express-generator @ 4

$ express / tmp / foo && cd / tmp / foo

Con eso logrado, puede usar NPM para instalar todas las dependencias necesarias e iniciar el servidor, según el contenido del archivo package.json creado por el generador:

$ npm instalar

$ npm inicio

Es difícil elegir lo más destacado de los más de un millón de paquetes en el NPM, pero algunas categorías se destacan. Express es el ejemplo más antiguo y destacado de los marcos de trabajo de Node.js. Otra categoría importante en el repositorio de NPM son las utilidades de desarrollo de JavaScript, incluido browserify, un paquete de módulos; bower, el administrador de paquetes del navegador; gruñido, el ejecutor de tareas de JavaScript; y gulp, el sistema de compilación de transmisión. Finalmente, una categoría importante para los desarrolladores empresariales de Node.js son los clientes de bases de datos, de los cuales hay más de 8,000, incluidos módulos populares como redis, mongoose, firebase y pg, el cliente PostgreSQL.

En resumen, Node.js es un entorno de ejecución de JavaScript multiplataforma para servidores y aplicaciones. Se basa en un bucle de eventos sin bloqueo de un solo subproceso, el motor JavaScript de Google Chrome V8 y una API de E / S de bajo nivel. Varias técnicas, incluido el módulo de clúster, permiten que las aplicaciones de Node.js escalen más allá de un solo núcleo de CPU. Más allá de su funcionalidad principal, Node.js ha inspirado un ecosistema de más de un millón de paquetes que están registrados y versionados en el repositorio de NPM y se pueden instalar usando la línea de comandos de NPM o una alternativa como Yarn.