- Conocer la motivación que llevó a la creación de Node.js y su arquitectura interna básica para tener suficiente información y poder tomar decisiones informadas acerca de si Node.js es la herramienta adecuada para resolver un problema específico.
- Conocer y comprender objetos y clases base que provee la plataforma. Entender el sistema de módulos que usa Node.js y algunos módulos base muy importantes.
Node.js es un ambiente de ejecución de aplicaciones JavaScript basado en el motor V8, uno de los componentes principales del navegador Google Chrome. Utiliza un modelo de programación basado en eventos, con I/O no bloqueante y se complementa con NPM y módulos que siguen la arquitectura CommonJS para extender su funcionalidad. Fue creado en 2009 por Ryan Dahl en Joyent y actualmente administrado por la Linux Foundation.
La motivación de su desarrollo fue lograr que los servidores de aplicaciones manerjaran los eventos de I/O de manera asíncrona con un sistema basado en eventos, a diferencia de uno de los servidores más populares de la época, Apache, que está basado en un esquema multithreaded y degrada su performance e incrementa linealmente el uso de recursos del servidor a medida que aumenta la carga de usuarios.
Node.js está escrito en C++ e integra V8, motor de ejecución de JavaScript, con libuv, librería que maneja event-loops y permite realizar operaciones de I/O asíncronas, como por ejemplo: acceso al sistema de archivos, a protocolos TCP y DNS.
Node.js fue desarrollado bajo la supervisión de Joyent hasta la versión 0.12. Problemas internos dentro del equipo técnico hicieron que a fines de 2014 se dividiera dicho equipo y ahí comenzó el trabajo sobre io.js, versión basada en Node.js pero con nuevas características como ser versiones de V8 actualizadas y soporte para ES6. A mediados de 2015, luego de que io.js hubiera recibido mucho apoyo por parte de la comunidad, se decidió volver a unir los proyectos, lo que derivó en el traspaso de la gestión a la Linux Foundation y la versión 4.0.0 de Node.js, liberada en septiembre de 2015.
Node.js trae integrado un ambiente de ejecución o REPL (Read-Eval-Print-Loop) que permite ingresar comandos y ejecutarlos inmediatamente. Para acceder, solo se debe ejecutar el comando:
> node
En la línea de comandos se tiene acceso completo a todas las funcionalidades de Node.js. Este entorno estuvo pensado desde el principio para tener la mayor similitud al entorno de ejecución de JavaScript en un navegador. Por ejemplo, para demorar la ejecución de una función en una página web se utiliza la función setTimeout
que se encuentra disponible en el objeto global. En Node.js, también existe una función setTimeout
con la misma sintaxis y propósito, y también es parte del objeto global del entrono de ejecución. Así, muchas otras propiedades, objetos y funciones fueron replicadas desde el entorno de los navegadores al entorno de Node.js.
Por ejemplo, un objeto que es exclusivo de Node.js es process
, a través del cual se tiene acceso a funciones de entrada/salida y manejo del propio proceso de ejecución. Por ejemplo, para forzar a que termine un programa de Node.js se debe ejecutar:
process.exit(); // fuerza a que el procesamiento termine
Para recibir una notificación de que el programa va a ser terminado por el sistema operativo, y poder tomar acciones al respecto, se debe escuchar el evento SIGINT
:
process.addListener("SIGINT", function () { // escucha `Ctrl-C` o `kill -2`
console.log("Terminando el proceso...");
process.exit(1);
});
setInterval(function () {
console.log(process.pid); // imprime el id de proceso actual
}, 1000);
El objeto process
también tiene otras propiedades muy frecuentemente usadas como env
, que contiene todas las variables de entorno del sistema operativo, stdin
/stdout
/stderr
, para manejar la entrada/salida del process, argv
, conteniendo los parámetros con los que fue invocado el proceso, etc.
Escribir un programa que reciba números por línea de comandos y los sume.
> node suma.js 2 5 12
> 19
Extender el programa anterior para que sume o saque promedio de acuerdo a una variable ambiente NODE_OP
(suma
o prom
).
> NODE_OP=prom node op.js 2 5 12
> 6.333333333333333
Node.js utiliza un sistema de módulos que permiten extender la funcionalidad básica del entorno, basado en el proyecto CommonJS. El objetivo de este proyecto, iniciado en 2009 por Kevin Dangoor de Mozilla, era generar un ecosistema de JavaScript que se extendiera más allá de los navegadores e incluyera diferentes entornos de programación como servidores y programas de escritorio.
Hay una serie de módulos que forman parte del entorno de Node.js y que pueden ser utilizados directamente. Por ejemplo, para realizar operaciones con el sistema de archivos, se debe hacer lo siguiente:
var fs = require("fs");
fs.readFile("ruta/al/archivo", callback);
Los módulos son, entonces, instanciados utilizando la función global require()
, la que devuelve un objeto conteniendo todas las propiedades públicas, objetos y funciones, que forman parte de la interfaz (API) de dicho módulo.
Éste módulo nos permite realizar operaciones contra el sistema de archivos del equipo donde está corriendo el programa. Todas las operaciones tienen una versión sícrónica y una asincrónica. Las variantes sincrónicas no deberán ser utilizadas en entornos donde la carga de trabajo sea importante ya que bloquean la ejecución de todo el programa hasta ser completadas.
Las operaciones más comunes incluyen:
fs.readFile
fs.writeFile
fs.appendFile
fs.stat
fs.rename
fs.mkdir
fs.readdir
fs.rmdir
Para leer un archivo de texto y mostrarlo en pantalla, se utiliza fs.readFile
de la siguiente manera:
var fs = require("fs");
fs.readFile("archivo.txt", "utf8", function (err, data) {
if (err) {
throw err;
}
console.log(data);
});
Si no se especifica la codificación del archivo a ser leído, readFile
devuelve los datos crudos que representan el contenido del archivo. Los archivos de texto usan comunmente la codificación será utf8
.
Crear un programa que simule el comando cat
de Unix o type
de Windows: debe recibir un nombre de archivo como parámetro e imprimir por pantalla el contenido del archivo.
Bonus: Crear un archivo bash
o bat
que simplifique la sintaxis a:
> node-cat mi-archivo.txt
Crear un programa que, dada una ruta, imprima el nombre de todos los archivos de ese directorio.
Bonus: Si se recibe un parámetro adicional, por ejemplo txt
, mostrar solo los archivos que tengan esa extensión.
Crear un programa que renombre un archivo recibiendo dos parámetros: nombre actual y nuevo nombre. Adicionalmente, debe agregar el texto "// Archivo renombrado a [nuevo-nombre]" al final del mismo. Finalmente, debe imprimir por pantalla el nuevo contenido del archivo.
npm
, "Node Package Manager", es una herramienta que viene junto con Node.js y sirve principalmente para administrar los módulos que componen una aplicación JavaScropt. Sus principales componenetes son:
- Herramineta
npm
: permite la ejecución de diferentes comandos para administrar módulos - Archivo
package.json
: contine datos sobre la configuración de la aplicación - Registro
npmjs.org
: almacena todos los módulos públicos existentes
El archivo package.json
, entones, es una pieza fundamental en en entorno de programación de Node.js. Éste archivo contiene un objeto JSON (y no un objeto JavaScript) con información esencial sobre el programa o módulo que estamos desarrollando o utilizando, como así también sus dependencias y comandos para automatizar los ciclos de trabajo, entre otras cosas.
Si, por ejemplo, se desarrolla un programa basado en Express.js, en el archivo package.json
debe a existir una entrada así:
{
"dependencies": {
"express": "^4.0.0"
}
}
Lo anterior especifica que el programa depende del módulo express
y que la versión requerida es cualquiera de la serie 4.x.
Una vez definidas las dependencias en el archivo, el comando npm install
busca los módulos en el registro público y los instala localmente en la carpeta node_modules
. A su vez, si un módulo depende de otros módulos, npm
resolverá estas dependencias automáticamente. Finalmente, dentro del programa se podrá utilizar el módulo como si fuera uno de los módulos que vienen incluidos en Node.js:
var express = require("express");
Existe también la posibilidad de instalar y actualizar el archivo package.json
en un solo paso utilizando la siguiente sintaxis:
> npm install --save express
El comando anterior buscará el módulo "express" en el registro, lo instalará localmente y actualizará el archivo package.json
con el número de versión correspondiente.
Existen casos en los cuales un módulo no se utiliza durante el funcionamiento productivo del programa sino que es solo útil durante el desarrollo. Casos como éste son los módulos de automatización de pruebas como mocha
. Utilizando la opción --save-dev
, se instalará el módulo pero se incluirá en la sección devDependencies
del package.json
.
Las versiones de los paquetes siguen, usualmente, la convención "semver" o "Semantic Versioning". Esta convención numera las versiones con el formato MAYOR.MENOR.PARCHE, donde cada parte se incrementa si:
- MAYOR: se incrementa cuando la nueva versión no es compatible con la anterior
- MENOR: se incrementa cuando se agregan funcionalidades y se mantiene compatibilidad
- PARCHE: se incrementa cuando se corrigen errores, sin agregar funcionalidad y manteniendo compatibilidad
En las dependencias definidas en el archivo package.json
, se pueden especificar versiones exactas de módulos o también rangos. Por ejemplo:
- 4.3.0: versión exacta igual a 4.3.0
- ~4.3.0: cualquier versión 4.3.x
- ^4.3.0: cualquier versión entre 4.3.0 y anterior a 5.x
Otras propiedades o secciones del archivo package.json
que son muy utilizadas son las siguientes:
name
: nombre del módulo o aplicación, que debe ser único si se va a publicarversion
: versión del módulo o aplicación, siguiendo en lo posible la convención semverdescription
: breve descripción del módulo o aplicación, en una líneascripts
: define comandos que se pueden correr para automatizar distintas tareas de desarrolloprivate
: si el módulo es privado y esta propiedad estrue
, evita una publicación accidental
- Video Node.js, Evented I/O for V8 Javascript, Ryan Dalh, JSConf EU 2009
- Documentación de la API de Node.js
- Video What the heck is the event loop anyway?, Philip Roberts, JSConf EU 2014
- Taller learnyounode de Nodeshool.
- Taller How to npm de Nodeshool.
- Especificación del archivo
package.json
en npmjs.com. - Registro de paquetes de Node.js: https://www.npmjs.com/
- ¿Qué es NPM?
- Semantic versioning
- Node and npm Version Numbering: Guide and Best Practices