Skip to main content Link Menu Expand (external link) Document Search Copy Copied

Intro a Node JS

Contenidos
  1. Javascript y Node
  2. Modo REPL
  3. Procesos y ejecución de scripts

Node JS es un entorno de ejecución de Javascript fuera del Navegador. Según palabras de su creador, NodeJS es un montón de Azucar construido sobre una compleja máquina virtual de alta performance creada por Google llamada V8. V8 se encarga de ejecutar deforma eficiente las tareas que Javascript le solicita. En este entorno Javascript se ejecuta en un solo hilo, pero es V8 quien ejecuta las tareas en forma paralela y notifica a Javascript cuando están completadas con ayuda del Event Loop y el Callstack.

Entonces, NodeJS es un set de librerías sobre V8 que utiliza su “grandeza” para hacer Networking Applications

En palabras de su creador Ryan Dahl, es una herramienta más o menos de propósito general, pero principalmente pensada para hacer aplicaciones en red Networking.

Es una herramienta de bajo nivel que cuenta con módulos core para ciertas funcionalidades frecuentes en este tipo de aplicaciones.

En esta unidad revisaremos cómo utilizar NodeJS para ejecutar scripts simples desde nuestra terminal de comandos.

Con NodeJS podemos hacer programación asíncrona y procesar cosas en paralelo sin tener que coordinar diferentes hilos de ejecución.

Javascript y Node

NodeJS fue escrito en JavaScript y con mucha similitud a la API del navegador en la mayoría de los casos. NodeJS no puede detenerse, mientras exista trabajo que hacer, siempre estará despierto. A diferencia de otros lenguajes de programación dónde las instrucciones tipo (sleep), detienen la ejecución del intérprete. NodeJS no se puede detener, pasará a realizar la siguiente acción pendiente. Mira el siguiente ejemplo

En lenguajes como python, tendríamos que escribir de esta forma el código para obtener el mismo resultado.

print("Hello")
sleep(2)
print("world")

Node no espera mientras hace solicitudes en red. Por ejemplo al solicitar una URL externa, NodeJS no se detiene a esperar la respuesta. Node sigue con la siguiente tarea y reaccionará cuando la solicitud retorne y emita algún evento para retomar su procesamiento, pero en el intertanto estuvo todo el tiempo ejecutando otras tareas. En otras palabras Node se podría desactivar mientras espera, pero nunca se detiene si hay algo por hacer.

En el ejemplo anterior el programa no termina de ejecutar ya que setInterval nos muestra una propiedad importante de NodeJS. Si hay callbacks pendientes por ejecutar no se detendrá. Lo que ocurre muy frecuente en Network Applications al esperar una respueta HTTP con un callback asociado.

¿Por qué NodeJS se hizo con JavaScript y no otro lenguaje?

  1. Las funciones son objetos y además Closures. Muy conveniente para aplicaciones en RED.
  2. El 100% de las librerias de JavaScript funciona bajo el paradigma de eventos asíncronos.[6]

Para finalizar esta introducción podemos decir que NodeJS trajo un modelo de ejecución considerado poco convensional para el 2011. Como ejemplo con Apache (uno de los servidores web más populares), el manejo de varias solicitudes HTTP se debe lograr mediante un pool de threads o hilos de ejecución y cada uno puede quedar esperando cuando ocurren operaciones I/O bloqueantes (leer archivos, consultar a la bdd, etc). NodeJS se ejecuta en un solo hilo deejecución y si requiere hacer alguna operación con latencia, simplemente solicita la operación y continúa haciendo otros trabajos y cuando la operación finaliza, retoma su despacho ejecutando un callback asíncrono[6]. Podemos ver un pseudo ejemplo en el siguiente bloque:

var sql = "SELECT * FROM table";
database.query(sql, function(results) {
// procesar el resultado en este callback
});
// Hacer otras cosas en lugar de esperar

Modo REPL

REPL significa lectura (read), evaluación (eval), impresión (print), bucle (loop), y es una forma muy conveniente de probar rápidamente comandos simples de JavaScript y Node. Podemos escribir cualquier sentencia JavaScript modeo REPL, por ejemplo, una llamada Math.random, y luego presiona Enter, y Node leerá la línea, la evaluará, imprimirá el resultado y luego volverá a esperar para más líneas. El paso de impresión sucede automáticamente. No necesitamos agregar ninguna instrucción para imprimir el resultado. Node simplemente imprimirá el resultado de cada línea que escriba. Esto es genial, pero tenga en cuenta que algunas líneas no tendrán ningún resultado. El Nodo REPL imprimirá undefined en este caso. Por ejemplo, si define una variable como esta:

let respuesta = 42

Y presiona Enter, verá undefined. Esto se debe a que esta es una declaración en JavaScript. No es una expresión. No tiene ninguna salida, y es por eso que REPL imprimió undefined como la salida de esta declaración. Por otro lado, escribamos una expresión, por ejemplo, 3 == "3" el carácter. Esta es una expresión booleana. Por cierto, ¿pregunta rápida? ¿Crees que esta expresión se evalúa como verdadera o falsa? Bueno, este es un tipo de pregunta que se puede responder fácilmente dentro de un Nodo REPL. Lo escribes muy rápido y presionas Enter, y ahí lo tienes, esto es true. Entonces, esta línea era una expresión de JavaScript, y REPL imprimió su resultado para nosotros. A veces, la expresión que necesitamos probar puede necesitar varias líneas. Digamos que desea definir una función que genere la fecha de hoy y pruébela. Comenzará con el nombre de la función, y luego comenzará con una llave, podemos presionar Enter aquí. El modo REPL de NodeJS es lo suficientemente inteligente como para detectar que la sentencia aún no ha terminado, y entrará en este modo de varias líneas para que escribir más.

Además, Node tiene un editor con más funciones aquí dentro del REPL. Escribe .editor para abrirlo y, cuando lo haga, podemos escribir tantas líneas como necesitemos. Por ejemplo, puede definir varias funciones o pegar código desde el portapapeles. Cuando termine de escribir, presione Ctrl+D para que REPL evalúe su código. Todas las funciones que definió en el editor ahora estarán disponibles en su sesión REPL. El comando .editor es un comando REPL, y en realidad hay algunos otros comandos. Puede ver la lista escribiendo el comando .help. El comando .break, o su alias .clear, le permite salir de algunos casos extraños en la sesión REPL. Por ejemplo, cuando pega algún código en el modo multilínea de Node y no está seguro de cuántas llaves necesita para llegar a un estado ejecutable, puede descartar completamente el código pegado usando un comando .break. Esto le evita matar toda la sesión para salir de situaciones simples como esta. El comando .exit sale de REPL, o simplemente puede presionar Ctrl+D. Los comandos .load y .save se pueden usar para generar y usar scripts de Node externos dentro de su REPL. En una nueva sesión de REPL, y digamos que escribimos en esta sesión de REPL, y definimos una función, y luego otra función, y luego una tercera función, y ahora tengo algo de historial en esta sesión de REPL, y lo que quiero hacer es guardar todas estas funciones en un archivo externo para quizás revisarlas más tarde o quizás confirmarlas para obtenerlas. Todo lo que necesito hacer es .save y darle un nombre de archivo, si más tarde comenzamos una nueva sesión REPL y quisiéramos redefinir las funciones que definimos previamente en el archivo, todo lo que tenemos que hacer es usar el comando .load con el nombre del archivo como argumento, y Node cargará todas las líneas en el archivo y las evaluará. Y ahora tenemos acceso a las funciones y variables definidas en ese archivo.

$ node
...

Además del comando global node, después de la intalación, también tenemos disponibles los comandos npm y npx. El primero nos ayuda a instalar y gestionar dependencias en los proyectos, mientras que el segundo

Prueba Tab y doble Tab en el modo REPL

Además de tener JavaScript en la consola. NodeJS viene com potentes librerías para crear servidores en Network Applications. Crea el siguiente ejemplo en un archivo llamado web-server.js.

const http = require('http');
var s = http.createServer((req,res)=>{
  res.writeHead(200,{'content-type': 'text/plain'})
  res.end("Hello World") // Our Body
})

s.listen(8000)

$ node web-server.js

y en una segunda terminal $ curl -i http://localhost:8080, o en el navegador. La salida debiera ser similar a esto

HTTP/1.1 200 ok
content-type: text-plain
Connection: keep-alive
Transfer-Encoding: chunked

Hello World

La cabecera Connection con el valor keep-alive permite que se cree una sola conexión persistente con el servidor mediante la cual se pueden enviar varias solicitudes. Antes por cada solicitud se debía establecer una conexión con el servidor. Mientras que Transfer-Encoding con el valor chunked nos permite enviar la respuesta por partes (streaming). Veamos el siguiente ejemplo:

const http = require('http');
var s = http.createServer((req,res)=>{
  res.writeHead(200,{'content-type': 'text/plain'})
  res.write("Hello\n")
  setTimeout(()=>{
    res.end("World\n")
  },2000)
})

s.listen(8000)

Es frecuente que no sepamos de qué porte pueda ser una respuesta en una aplicación, como cuando se consulta una base de datos, podría entregar entre 0 o miles de registros. En ese caso, en cuanto comienza a recibir la información, NodeJS comienza a enviar la respuesta y no la acumula en la memoria del servidor

Procesos y ejecución de scripts

Podemos pasar una ruta, absoluta o relativa a NodeJS y este evaluará su contenido. Si el archivo tiene un proceso permanente, como un servidor escuchando en un puerto, NodeJS quedará utilizando la terminal hasta que se detenga forzosamente con Ctrl+D. Pero si el script no tiene una tarea permanente, ejecutará el còdigo y luego terminará.