Node.js para principiantes
Spanish (Español) translation by Elías Nicolás (you can also view the original English article)
La programación basada en eventos puede ser abrumadora para los principiantes, lo que puede hacer que Node.js sea difícil de comenzar. Pero no dejes que eso te desanime; En este artículo, te enseñaré algunos de los conceptos básicos de Node.js y explicaré por qué se ha vuelto tan popular.
Introducción
Para empezar a utilizar Node.js, primero debe comprender las diferencias entre Node.js y los entornos de scripts tradicionales del lado del servidor (por ejemplo: PHP, Python, Ruby, etc.).
Programación asincrónica
Node.js utiliza una arquitectura de módulo para simplificar la creación de aplicaciones complejas.
Es probable que esté familiarizado con la programación asincrónica; es, después de todo, la "A" en Ajax. Cada función en Node.js es asincrónica. Por lo tanto, todo lo que normalmente bloquearía el hilo se ejecuta en segundo plano. Esto es lo más importante para recordar acerca de Node.js. Por ejemplo, si está leyendo un archivo en el sistema de archivos, debe especificar una función de devolución de llamada que se ejecuta cuando se completa la operación de lectura.
¡Estás haciendo todo!
Node.js es solo un entorno, lo que significa que tienes que hacer todo tú mismo. No hay un servidor HTTP predeterminado, o cualquier servidor. Esto puede ser abrumador para los nuevos usuarios, pero la recompensa es una aplicación web de alto rendimiento. Una secuencia de comandos maneja todas las comunicaciones con los clientes. Esto reduce considerablemente la cantidad de recursos utilizados por la aplicación. Por ejemplo, aquí está el código para una aplicación simple Node.js:
1 |
var i, a, b, c, max; |
2 |
|
3 |
max = 1000000000; |
4 |
|
5 |
var d = Date.now(); |
6 |
|
7 |
for (i = 0; i < max; i++) {
|
8 |
a = 1234 + 5678 + i; |
9 |
b = 1234 * 5678 + i; |
10 |
c = 1234 / 2 + i; |
11 |
} |
12 |
|
13 |
console.log(Date.now() - d); |
Y aquí está el equivalente escrito en PHP:
1 |
$a = null; |
2 |
$b = null; |
3 |
$c = null; |
4 |
$i = null; |
5 |
$max = 1000000000; |
6 |
|
7 |
$start = microtime(true); |
8 |
|
9 |
for ($i = 0; $i < $max; $i++) { |
10 |
$a = 1234 + 5678 + $i; |
11 |
$b = 1234 * 5678 + $i; |
12 |
$c = 1234 / 2 + $i; |
13 |
}
|
14 |
|
15 |
var_dump(microtime(true) - $start); |
Ahora veamos los números de referencia. La siguiente tabla enumera los tiempos de respuesta, en milisegundos, para estas dos aplicaciones simples:
| Cantidad de iteraciones | Node.js | PHP |
| 100 | 2.00 | 0.14 |
| 10'000 | 3.00 | 10.53 |
| 1'000'000 | 15.00 | 1119.24 |
| 10'000'000 | 143.00 | 10621.46 |
| 1'000'000'000 | 11118.00 | 1036272.19 |
Ejecuté las dos aplicaciones desde la línea de comandos para que ningún servidor demorara la ejecución de las aplicaciones. Ejecuté cada prueba diez veces y promedié los resultados. PHP es notablemente más rápido con una menor cantidad de iteraciones, pero esa ventaja se disuelve rápidamente a medida que aumenta el número de iteraciones. ¡Cuando todo está dicho y hecho, PHP es un 93% más lento que Node.js!
Node.js es rápido, pero deberá aprender algunas cosas para usarlo correctamente.
Módulos
Node.js utiliza una arquitectura de módulo para simplificar la creación de aplicaciones complejas. Los módulos son similares a las bibliotecas en C, o unidades en Pascal. Cada módulo contiene un conjunto de funciones relacionadas con el "tema" del módulo. Por ejemplo, el módulo http contiene funciones específicas de HTTP. Node.js proporciona algunos módulos básicos listos para usar para ayudarlo a acceder a los archivos en el sistema de archivos, crear servidores HTTP y TCP / UDP y realizar otras funciones útiles.
Incluir un módulo es fácil;
simplemente llame a la función require(), así:
1 |
var http = require('http');
|
Node.js es solo un entorno; tienes que hacer todo tú mismo.
La función require() devuelve la referencia al módulo especificado. En
el caso de este código, una referencia al módulo http se almacena en la
variable http.
En el código anterior, pasamos el nombre de un módulo a la
función require(). Esto hace que Node busque una carpeta node_modules en el directorio de nuestra aplicación y busca el módulo http en esa
carpeta. Si
el node no encuentra la carpeta node_modules (o el módulo http dentro
de ella), entonces busca a través de la memoria caché del módulo global. También puede especificar un archivo real pasando una ruta relativa o
absoluta, de la siguiente manera:
1 |
var myModule = require('./myModule.js');
|
Los módulos son piezas encapsuladas de código. El
código dentro de un módulo es en su mayoría privado, lo que significa
que las funciones y variables definidas dentro de ellas solo son
accesibles desde el interior del módulo. Sin embargo, puede exponer las
funciones y / o variables que se utilizarán fuera del módulo. Para
hacerlo, use el objeto exports y llene sus propiedades y métodos
con los fragmentos de código que desea exponer. Considere el siguiente
módulo como un ejemplo:
1 |
var PI = Math.PI; |
2 |
|
3 |
exports.area = function (r) {
|
4 |
return PI * r * r; |
5 |
}; |
6 |
|
7 |
exports.circumference = function (r) {
|
8 |
return 2 * PI * r; |
9 |
}; |
Este código crea una variable PI a la que solo se puede acceder mediante el código contenido dentro del módulo; no es accesible fuera del módulo. A continuación, se crean dos funciones en el objeto exports. Estas funciones son accesibles fuera del módulo porque están definidas
en el objeto exports. Como resultado, PI está completamente
protegido de interferencias externas. Por
lo tanto, puede estar seguro de que el area() y la circumference() siempre se comportarán como deberían (siempre que se proporcione un
valor para el parámetro r).
Entorno global
Node es un entorno de
JavaScript que se ejecuta en el motor de JavaScript V8 de Google. Como
tal, debemos seguir las mejores prácticas que usamos para el desarrollo
del lado del cliente. Por ejemplo, debemos evitar poner algo en el
alcance global. Eso, sin embargo, no siempre es posible. El
ámbito global en Node es GLOBAL (a diferencia de window en el
navegador), y puede crear fácilmente una variable global de función
omitiendo la palabra clave var, como esta:
1 |
globalVariable = 1; |
2 |
globalFunction = function () { ... };
|
Una vez más, los globales deben evitarse siempre que sea posible. Así que ten cuidado y recuerda usar var cuando declares una
variable.
Instalación
Naturalmente, necesitamos instalar Node antes de poder escribir y ejecutar una aplicación. La instalación es directa, si usa Windows o OS X; el sitio web nodejs.org ofrece instaladores para esos sistemas operativos. Para Linux, use cualquier administrador de paquetes. Abre tu terminal y escribe:
1 |
sudo apt-get update |
2 |
sudo apt-get install node |
o:
1 |
sudo aptitude update |
2 |
sudo aptitude install node |
Node.js está en repositorios de sid; Es posible que deba agregarlos a su lista de fuentes:
1 |
sudo echo deb http://ftp.us.debian.org/debian/ sid main > /etc/apt/sources.list.d/sid.list |
Pero tenga en cuenta que instalar paquetes sid en sistemas más antiguos puede dañar su sistema. Tenga cuidado y elimine /etc/apt/sources.list.d/sid.list después de
terminar de instalar Node.
Instalación de nuevos módulos
Node.js tiene un administrador de paquetes, llamado Node Package Manager (NPM). Se instala automáticamente con Node.js y utiliza NPM para instalar nuevos módulos. Para instalar un módulo, abra su terminal / línea de comando, navegue hasta la carpeta deseada y ejecute el siguiente comando:
1 |
npm install module_name |
No importa qué sistema operativo tenga; el comando anterior instalará el módulo que especifique en lugar de module_name.
La aplicación Hello World
Naturalmente, nuestro primer script Node.js
imprimirá el texto 'Hello World!' a la consola. Cree un archivo, llamado
hello.js, y escriba el siguiente código:
1 |
console.log('Hello World!');
|
Ahora ejecutemos el script. Abra la línea de comando / terminal, navegue a la carpeta que contiene hello.js y ejecute el siguiente comando:
1 |
node hello.js |
Deberías ver 'Hello World!' mostrado en la consola.
Servidor HTTP
Pasemos a una aplicación más avanzada; no es tan complicado como crees. Comencemos con el siguiente código. Lea los comentarios y luego la explicación a continuación:
1 |
// Include http module. |
2 |
var http = require("http");
|
3 |
|
4 |
// Create the server. Function passed as parameter is called on every request made. |
5 |
// request variable holds all request parameters |
6 |
// response variable allows you to do anything with response sent to the client. |
7 |
http.createServer(function (request, response) {
|
8 |
// Attach listener on end event. |
9 |
// This event is called when client sent all data and is waiting for response. |
10 |
request.on("end", function () {
|
11 |
// Write headers to the response. |
12 |
// 200 is HTTP status code (this one means success) |
13 |
// Second parameter holds header fields in object |
14 |
// We are sending plain text, so Content-Type should be text/plain |
15 |
response.writeHead(200, {
|
16 |
'Content-Type': 'text/plain' |
17 |
}); |
18 |
// Send data and end response. |
19 |
response.end('Hello HTTP!');
|
20 |
}); |
21 |
// Listen on the 8080 port. |
22 |
}).listen(8080); |
Este código es muy simple. Puede enviar más datos al cliente utilizando el método response.write(), pero debe llamarlo antes de llamar a response.end(). Guarde este
código como http.js y escriba esto en su consola:
1 |
node http.js |
Abra su navegador y navegue a http://localhost:8080. Debería ver el texto "Hello HTTP!" en la página.
Manejo de parámetros de URL
Como mencioné anteriormente, tenemos que hacer todo nosotros mismos en Node, incluidos los argumentos de solicitud. Esto es, sin embargo, bastante simple. Eche un vistazo al siguiente código:
1 |
// Include http module, |
2 |
var http = require("http"),
|
3 |
// And url module, which is very helpful in parsing request parameters. |
4 |
url = require("url");
|
5 |
|
6 |
// Create the server. |
7 |
http.createServer(function (request, response) {
|
8 |
// Attach listener on end event. |
9 |
request.on('end', function () {
|
10 |
// Parse the request for arguments and store them in _get variable. |
11 |
// This function parses the url from request and returns object representation. |
12 |
var _get = url.parse(request.url, true).query; |
13 |
// Write headers to the response. |
14 |
response.writeHead(200, {
|
15 |
'Content-Type': 'text/plain' |
16 |
}); |
17 |
// Send data and end response. |
18 |
response.end('Here is your data: ' + _get['data']);
|
19 |
}); |
20 |
// Listen on the 8080 port. |
21 |
}).listen(8080); |
Este código usa el método parse() del módulo url, un módulo Core Node.js, para convertir la URL de la solicitud a un objeto. El objeto devuelto tiene una propiedad query, que recupera los
parámetros de la URL. Guarde este archivo como get.js y ejecútelo con el
siguiente comando:
1 |
node get.js |
Luego, navegue a http://localhost:8080/?data=put_some_text_here en su navegador. Naturalmente, cambiar el valor del parámetro data no romperá la
secuencia de comandos.
Leer y escribir archivos
Para administrar archivos
en Node, usamos el módulo fs (un módulo principal). Leemos y escribimos
archivos usando los métodos fs.readFile() y fs.writeFile(),
respectivamente. Explicaré los argumentos después del siguiente código:
1 |
// Include http module, |
2 |
var http = require("http"),
|
3 |
// And mysql module you've just installed. |
4 |
fs = require("fs");
|
5 |
|
6 |
// Create the http server. |
7 |
http.createServer(function (request, response) {
|
8 |
// Attach listener on end event. |
9 |
request.on("end", function () {
|
10 |
// Read the file. |
11 |
fs.readFile("test.txt", 'utf-8', function (error, data) {
|
12 |
// Write headers. |
13 |
response.writeHead(200, {
|
14 |
'Content-Type': 'text/plain' |
15 |
}); |
16 |
// Increment the number obtained from file. |
17 |
data = parseInt(data) + 1; |
18 |
// Write incremented number to file. |
19 |
fs.writeFile('test.txt', data);
|
20 |
// End response with some nice message. |
21 |
response.end('This page was refreshed ' + data + ' times!');
|
22 |
}); |
23 |
}); |
24 |
// Listen on the 8080 port. |
25 |
}).listen(8080); |
Node.js tiene un administrador de paquetes, llamado Node Package Manager (NPM). Se instala automáticamente con Node.js
Guarde esto como files.js. Antes de ejecutar este script, cree un archivo llamado test.txt en el mismo directorio que files.js.
Este código demuestra los métodos fs.readFile()
y fs.writeFile(). Cada
vez que el servidor recibe una solicitud, la secuencia de comandos lee
un número del archivo, incrementa el número y escribe el nuevo número en
el archivo. El método fs.readFile() acepta tres
argumentos: el nombre del archivo a leer, la codificación esperada y la
función de devolución de llamada.
Escribir en el archivo, al menos en
este caso, es mucho más simple. No es necesario que esperemos ningún
resultado, aunque podría verificar si hay errores en una aplicación
real. El método fs.writeFile() acepta el nombre y los datos del archivo
como argumentos. También
acepta argumentos tercero y cuarto (ambos son opcionales) para
especificar la función de codificación y devolución de llamada,
respectivamente.
Ahora, ejecutemos este script con el siguiente comando:
1 |
node files.js |
Ábrelo en el navegador (http://localhost:8080) y actualícelo varias veces. Ahora, puede pensar que hay un error en el código porque parece
incrementarse en dos. Esto no es un error. Cada vez que solicita esta
URL, se envían dos solicitudes al servidor. La
primera solicitud la realiza automáticamente el navegador, que solicita
favicon.ico y, por supuesto, la segunda solicitud es para la URL (http://localhost:8080).
Aunque este comportamiento técnicamente no es un error, es un comportamiento que no queremos. Podemos solucionarlo fácilmente verificando la URL de solicitud. Aquí está el código revisado:
1 |
// Include http module, |
2 |
var http = require("http"),
|
3 |
// And mysql module you've just installed. |
4 |
fs = require("fs");
|
5 |
|
6 |
// Create the http server. |
7 |
http.createServer(function (request, response) {
|
8 |
// Attach listener on end event. |
9 |
request.on('end', function () {
|
10 |
// Check if user requests / |
11 |
if (request.url == '/') {
|
12 |
// Read the file. |
13 |
fs.readFile('test.txt', 'utf-8', function (error, data) {
|
14 |
// Write headers. |
15 |
response.writeHead(200, {
|
16 |
'Content-Type': 'text/plain' |
17 |
}); |
18 |
// Increment the number obtained from file. |
19 |
data = parseInt(data) + 1; |
20 |
// Write incremented number to file. |
21 |
fs.writeFile('test.txt', data);
|
22 |
// End response with some nice message. |
23 |
response.end('This page was refreshed ' + data + ' times!');
|
24 |
}); |
25 |
} else {
|
26 |
// Indicate that requested file was not found. |
27 |
response.writeHead(404); |
28 |
// And end request without sending any data. |
29 |
response.end(); |
30 |
} |
31 |
}); |
32 |
// Listen on the 8080 port. |
33 |
}).listen(8080); |
Pruébelo ahora; debería funcionar como se esperaba
Accediendo a bases de datos MySQL
La mayoría de las tecnologías tradicionales del lado del servidor tienen un medio incorporado para conectarse y consultar una base de datos. Con Node.js, debe instalar una biblioteca. Para este tutorial, elegí el node-mysql estable y fácil de usar. El nombre completo de este módulo es mysql@2.0.0-alpha2 (todo después de que @ es el número de versión). Abra su consola, navegue hasta el directorio donde ha guardado sus scripts y ejecute el siguiente comando:
1 |
npm install mysql@2.0.0-alpha2 |
Esto descarga e instala el módulo, y también crea la carpeta node_modules en el directorio actual. Ahora veamos cómo podemos usar esto en nuestro código; mira el siguiente ejemplo:
1 |
// Include http module, |
2 |
var http = require('http'),
|
3 |
// And mysql module you've just installed. |
4 |
mysql = require("mysql");
|
5 |
|
6 |
// Create the connection. |
7 |
// Data is default to new mysql installation and should be changed according to your configuration. |
8 |
var connection = mysql.createConnection({
|
9 |
user: "root", |
10 |
password: "", |
11 |
database: "db_name" |
12 |
}); |
13 |
|
14 |
// Create the http server. |
15 |
http.createServer(function (request, response) {
|
16 |
// Attach listener on end event. |
17 |
request.on('end', function () {
|
18 |
// Query the database. |
19 |
connection.query('SELECT * FROM your_table;', function (error, rows, fields) {
|
20 |
response.writeHead(200, {
|
21 |
'Content-Type': 'x-application/json' |
22 |
}); |
23 |
// Send data as JSON string. |
24 |
// Rows variable holds the result of the query. |
25 |
response.end(JSON.stringify(rows)); |
26 |
}); |
27 |
}); |
28 |
// Listen on the 8080 port. |
29 |
}).listen(8080); |
Consultar la base de datos con esta biblioteca es fácil; simplemente ingrese la cadena de consulta y la función de devolución de llamada. En
una aplicación real, debe verificar si hubo errores (el parámetro de
error no estará undefined si ocurrieron errores) y enviar códigos de
respuesta dependiendo del éxito o el fracaso de la consulta. También
tenga en cuenta que hemos configurado Content-Type en x-application/json, que es el tipo MIME válido para JSON. El
parámetro rows contiene el resultado de la consulta, y simplemente
convertimos los datos en rows en una estructura JSON utilizando el
método JSON.stringify(). .
Guarde este archivo como mysql.js y ejecútelo (si tiene MySQL instalado, eso es):
1 |
node mysql.js |
Navegue a http://localhost:8080 en su navegador, y se le debe pedir que descargue el archivo con formato JSON.
Conclusión
Cada función en Node.js es asincrónica.
Node.js requiere trabajo adicional, pero el beneficio de una aplicación rápida y robusta lo vale. Si no desea hacer todo en el nivel más bajo, siempre puede elegir algún marco, como >Express, para facilitar el desarrollo de aplicaciones.
Node.js es una tecnología prometedora y una excelente opción para una aplicación de carga alta. Ha sido probado por corporaciones, como Microsoft, eBay y Yahoo. Si no está seguro de alojar su sitio web / aplicación, siempre puede usar una solución VPS barata o varios servicios basados en la nube, como Microsoft Azure y Amazon EC2. Ambos servicios brindan entornos escalables a un precio razonable.
¡No olvides comentar si tienes alguna pregunta!



