Lugar
Fecha
- Sábado, 8 de Abril. 10:30-14:30
Contenido
- Charla de Flexbox con Ángel Corral Arias (@ancoar)
- Charla de Arduino Fran Acién (@amil101)
- Visionado de dos charlas sobre Arduino
Apuntate
Node.js es un entorno en tiempo de ejecución multiplataforma, de código abierto, para la capa del servidor (pero no limitándose a ello) basado en el lenguaje de programación ECMAScript, asíncrono, con I/O de datos en una arquitectura orientada a eventos y basado en el motor V8 de Google. Fue creado con el enfoque de ser útil en la creación de programas de red altamente escalables, como por ejemplo, servidores web. Fue creado por Ryan Dahl en 2009 y su evolución está apadrinada por la empresa Joyent, que además tiene contratado a Dahl en plantilla - Wikipedia
Otra manera es posible
Puntos Fuertes
- Asincronía (no bloqueo)
- Backend completo
- NPM (comunidad)
- Single thread (paralelismo)
- Librerías propias
- Utilidades
- Código abierto
- Basado en el V8 (escrito en C++) de Google
- Multiplataforma
- Orientado a Eventos
- No se limita solo a servidores HTTP
Librerías interesantes
- awesome Node.js
- Grunt
- Gulp
- Express
- Mongoose
- Socket.io
- Apache Cordova
- Async
- Chalk
- J5
- GraphicsMagick
- Marked
- Node-restify
- Webpack
- Morgan
- Nodemailer
- Passportjs
- Cheerio
- X-ray
- Bower
- PM2
- Electron
- Yeoman
- Babel
- Helmet
- Faker
- Protractor
- Nightwatch.js
- Cypress.io
IO.js
io.js has merged with the Node.js project again. There won't be any further io.js releases. All of the features in io.js are available in Node.js v4 and above.
Dependencias, dependencias, dependencias... y más dependencias
module.exports = leftpad;
function leftpad (str, len, ch) {
str = String(str);
var i = -1;
if (!ch && ch !== 0) ch = ' ';
len = len - str.length;
while (++i < len) {
str = ch + str;
}
return str;
}
- How one developer just broke Node, Babel and thousands of projects in 11 lines of JavaScript
- A discussion about the breaking of the Internet
- I’ve Just Liberated My Modules
- Left-pad en GitHub
- Is left-pad Indicative of a Fragile JavaScript Ecosystem?
- Overcoming JavaScript Fatigue
- One developer just broke Node, Babel and thousands of projects in 11 lines of JavaScript
- How 17 Lines of Code Took Down Silicon Valley’s Hottest Startups
- Npm package author revokes his packages, breaking tons of builds
- ¿Y si el software Open Source desapareciera?
- El programador que borró 11 líneas de código y se cargó Internet
Características estrella
- Code together in real time
- Share your IDE, your workspace, a preview, or your running app
- Replay all edits and see your code at any point in time
Otras características
- Preview in any browser
- Built-In Terminal
- Language Tools
- Debugger
- Split View
- Themes
- Run Panel
- Key Bindings Editor
- VIM/Emacs/Sublime Mode
- Built-In Image Editor
Más
-
Versiones:
- Pares -> Estables
- Impares -> inestables
-
Versiones LTS:
-
Grandes Cambios:
-
Comprobar version:
- Node
node -v
- Npm
npm -v
- Hola mundo!:
console.log("Hola Mundo!");
- Hola mundo! (retraso):
setTimeout(function() {
console.log("Hola Futuro...!");
}, 5000);
- Hola mundo! (repetición):
setInterval(function() {
console.log("Hola Futuro...!");
}, 1000);
console.assert(value[, message][, ...])
console.assert(true, 'No me muestro!');
console.assert(false, 'Me muestro');
console.time() y console.timeEnd()
console.time('100-elementos');
for (var i = 0; i < 100; i++) {
console.log(i);
}
console.timeEnd('100-elementos');
// 100-elementos: 5ms
Sustituciones
- %d Enteros y coma flotante
console.log("Tenemos %d usuarios conectados", 10);
- %s Cadenas
console.log("Tenemos %s usuarios conectados", "muchos");
- %j Objetos JSON
console.log("Tenemos %j", {alumnos:{total:15, estado:"conectados"}});
Los estados
- 0 Deprecated
- 1 Experimental
- 2 Unstable
- 3 Stable
- 4 API Frozen
- 5 Locked
Los módulos
- Buffer - Permite el trabajo con datos crudos
- C/C++ Addons - Permite integrar librerias de C/C++
- Child Processes - Permite crear y gestionar "procesos hijo"
- Cluster - Permite gestionar nuestro proceso principal e "hijos" entre diversos módulos
- Command Line Options - Controla el lanzamiento de Node por Consola
- Console - Permite trabajar con la consola (terminal), imitando la consola del navegador
- Crypto - Relacionado a las funcionalidades de criptografía necesarias apra algunso protocolos como SSL
- Debugger - Utilidades de depuración
- DNS - Gestion y resolución de nombres de Dominios
- Domain - DEPRECIADO
- Errors - Gestión de errores
- Events - Permite gestionar y crear eventos
- File System - Permite manipular y crear ficheros en el sistema
- Globals - Ámbito global
- HTTP - Gestión del protocolo HTTP
- HTTPS - Gestión del protocolo HTTPS (http y tls/ssl)
- Modules - Gestión y carga de módulos
- Net - Nos aporta una capa de red asíncrona y permite gestionar "streams" tanto cliente como servidor.
- OS - Información básica sobre el sistema operativo en el que estamos funcionando
- Path - Gestión de rutas dentro del sistema (navegación de carpetas y archivos)
- Process - Objeto global que gestiona el proceso del sistema que representa nuestra ejecución de Node
- Punycode - Sintaxís de codificación a RFC 3492 y RFC 5891
- Query Strings - Manipualción y gestion de cadenas URL
- Readline - Puede leer línea a línea información de entrada como la consola
- REPL - Read-Eval-Print-Loop (REPL)
- Stream - Interfaz abstracta usada por otros módulos para gestionar el flujo de la información
- Timers - Funciones globales de tiempo como setInterval, clearInterval, etc...
- TLS/SSL - Capa de encriptación basada en OpenSSL
- UDP/Datagram - Gestión del protocolo UDP
- URL - Facilita la resolución y parseo de URLs
- Utilities - Utilidades varias, la mayoría depreciadas
- V8 - Información sobre v8
- VM - Permite aislar código en "sandboxes"
- ZLIB - Permite trabajar con Gzip/Gunzip, Deflate/Inflate y DeflateRaw/InflateRaw
- Hello World con HTTP:
var http = require('http');
var puerto = 3000;
var direccion = "127.0.0.1";
var mensaje = 'Hola a todos, ahora usando HTTP\n';
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end(mensaje);
}).listen(puerto, direccion);
console.log('Server running at http://'+direccion+':'+puerto+'/');
- Hello World desde c9.io:
var http = require('http');
var mensaje = 'Hola a todos, ahora usando HTTP con C9.io\n';
http.createServer(function(req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end(mensaje);
}).listen(process.env.PORT, process.env.IP);
console.log('Server running at http://'+process.env.IP+':'+process.env.PORT+'/');
- Rediccionamiento:
var http = require('http');
http.createServer(function (req, res) {
res.writeHead(301, {
'Location': 'http://www.google.es/'
});
res.end();
}).listen(process.env.PORT, process.env.IP);
console.log('Servidor funcionando en http://'+process.env.IP+':'+process.env.PORT+'/');
- Ping (petición http):
var url = "google.es";
http.get({ host: url }, function(resOrigen) {
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end("La respuesta de " +url+" es "+resOrigen.statusCode );
console.log("La respuesta de " +url+" es "+resOrigen.statusCode );
}).listen(process.env.PORT, process.env.IP);
console.log('Servidor disponible en http://'+process.env.IP+':'+process.env.PORT+'/');
}).on('error', function(e) {
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end("La respuesta de " +url+" genera un error - " + e.message );
}).listen(process.env.PORT, process.env.IP);
console.log('Servidor disponible en http://'+process.env.IP+':'+process.env.PORT+'/');
console.log("Tenemos un error!! - " + e.message);
});
- Leyendo urls:
var url = require('url');
var demoURL = "http://localhost:3000/ruta?parametro=dato#detalle";
console.log("El host: "+url.parse(demoURL).hostname);
console.log("El puerto: "+url.parse(demoURL).port);
console.log("La ruta: "+url.parse(demoURL).pathname);
console.log("La parametro: "+url.parse(demoURL).query);
console.log("El hash(#): "+url.parse(demoURL).hash);
- Trabajando con rutas:
var http = require('http'),
url = require('url');
http.createServer(function (req, res) {
var pathname = url.parse(req.url).pathname;
if (pathname === '/') {
res.writeHead(200, {
'Content-Type': 'text/plain'
});
res.end('Index!');
} else if (pathname === '/otro') {
res.writeHead(200, {
'Content-Type': 'text/plain; charset=utf-8'
});
res.end('sencillamente otra página');
} else if (pathname === '/alindex') {
res.writeHead(301, {
'Location': '/'
});
res.end();
} else {
res.writeHead(404, {
'Content-Type': 'text/plain'
});
res.end('Querido... 404!');
}
}).listen(process.env.PORT, process.env.IP);
console.log('Servidor funcionando en http://'+process.env.IP+':'+process.env.PORT+'/');
- Ping recurrente (consola):
var http = require('http');
var url = "google.es";
var tiempo = 3500;
setInterval(function() {
http.get({ host: url }, function(res) {
if (res.statusCode === 200 ) {
console.log("Sin errores en " +url);
} else {
console.log("Respuesta Http "+res.statusCode+" en " +url);
}
}).on('error', function(e) {
console.log("Con errores -> La respuesta de "+url+" es "+e.message );
});
}, tiempo);
El modelo de programación de Node.js es monohilo, asíncrono y dirigido por eventos.
- No puede haber código bloqueante o todo el servidor quedará bloqueado y esto incluye no responder a nuevas peticiones entrantes.
- La asincronicidad implica que no sabemos cuándo ni en que orden se va a ejecutar el código, generalmente esto no es importante pero en ocasiones sí lo es y habrá que tenerlo en cuenta.
- En caso de error inesperado debemos capturarlo y controlar el posible estado en que haya podido quedar la ejecución del código.
Nicolas Nombela en nnombela
- Sincrónico - código bloqueante:
var http = require("http");
var numeroPeticion = 1
function writeResponse(response) {
response.writeHead(200, {"Content-Type": "text/plain"});
response.write("Hola Mundo!, numero de peticion "+numeroPeticion);
response.end();
console.log("Se termino... "+numeroPeticion);
}
function sleepSynch(seconds, response) {
var startTime = new Date().getTime();
while (new Date().getTime() < startTime + Math.floor((Math.random() * 1000) + 500) * seconds) {
// Nada pasa....
}
writeResponse(response);
}
http.createServer(function(request, response) {
console.log("Empezo... "+numeroPeticion);
sleepSynch(10, response);
numeroPeticion++;
}).listen(process.env.PORT);
console.log("en puerto ->" + process.env.PORT);
- Asincronico - timeOut()
var http = require("http");
function writeResponse(response) {
response.writeHead(200, {"Content-Type": "text/plain"});
response.write("Hola Mundo!");
response.end();
console.log("Se termino... ");
}
function sleepAsynch(seconds, response) {
setTimeout(function() {
writeResponse(response);
}, Math.floor((Math.random() * 1000) + 100) * seconds);
}
http.createServer(function(request, response) {
console.log("Empezo... ");
sleepAsynch(10, response);
}).listen(process.env.PORT);
console.log("en puerto ->" + process.env.PORT);
- Se cierra:
setTimeout(function (){
process.stdout.write("Cerrando Node...")
}, 1000)
- Se mantiene:
setInterval(function (){
// Nada pasa... pero sigo funcionando
}, 1000)
- Programando una salida:
var contador = 0
setInterval(function (){
contador++
if(contador > 10){
process.exit()
} else {
console.log("Sigo. Valor contador -> "+contador +"\n")
}
}, 1000);
- Leer un archivo
var fs = require('fs');
fs.readFile('archivo.txt', 'utf8', function (err, data) {
if (!err) {
console.log(data);
} else {
throw err;
}
});
- Escribir un archivo
var fs = require('fs'),
data = "y esto... se guardará en el archivo.txt";
fs.writeFile('archivo.txt', data, function (err) {
if (!err) {
console.log('Datos guardados en el archivo.txt');
} else {
throw err;
}
});
- Usando Promesas y Callbacks
var fs = require("fs");
// Con CallBacks!
fs.readFile("./miArchivo.txt", function(error, content){
console.log("Leyendo el archivo...");
fs.writeFile("./logitud.txt", content.length, function(error){
if (error) {
console.log("error! ", error);
} else {
console.log("Terminado... hemos almacenado una cadena que vale ",content.length);
}
});
});
// Con Promesas!
function leerArchivo (nombre) {
return new Promise(function(resolver, rechazar){
fs.readFile(nombre, function(error, contenido) {
console.log("Empezando la lectura de ", nombre);
if(error){
console.log("Error en la lectura");
return rechazar(error);
}
console.log("Lectura finalizada en ", nombre);
resolver(contenido);
});
});
}
function escribirArchivo (nombre, contenido){
return new Promise(function(resolver, rechazar){
fs.writeFile(nombre, contenido, function(error){
if(error){
console.log("Error en la escritura de ", nombre);
rechazar(error);
} else {
console.log("Escritura Termianda en ", nombre);
resolver();
}
});
});
}
//Opción1
leerArchivo("./miArchivo.txt")
.then(function(contenido){
escribirArchivo("./longitud.txt", contenido);
})
.catch(function(error){
console.log("Promesas con errores: ");
console.log(error);
});
//Opción2
Promise.all([
leerArchivo("./otros.txt"),
leerArchivo("./usuarios.txt"),
leerArchivo("./mas_cosas.txt")
]).then(function(respuestas){
console.log("Tenemos un total de "+respuestas.length+" respuesta/s.");
console.log("El primero tiene "+respuestas[0].length+" caracteres");
console.log("El segundo tiene "+respuestas[1].length+" caracteres");
console.log("El tercero tiene "+respuestas[2].length+" caracteres");
});
//Opcion3
Promise.race([
leerArchivo("./otros.txt"),
leerArchivo("./usuarios.txt"),
leerArchivo("./mas_cosas.txt")
]).then(function(respuesta){
console.log("El más rápido tiene solo "+respuesta.length+" caracteres.");
});
- Más métodos para:
- Síncronos
- Escucha de cambios
- Manipulación de carpetas
- etc...
-
Patrón Observador
-
Similar al navegador
-
Suscribiendonos a eventos
- Sin eventos
var http = require('http'); var server = http.createServer(function (request, response) { response.writeHead(200, {"Content-Type": "text/plain"}); response.end("¡Hola people!"); }).listen(process.env.PORT); console.log('Servidor escuchando por el puerto ' +process.env.PORT);
- Con eventos
var http = require('http'); var server = http.createServer().listen(process.env.PORT); server.on('request', function (request, response) { response.writeHead(200, {"Content-Type": "text/plain"}); response.end("¡Hola people!"); }); console.log('Servidor escuchando por el puerto ' +process.env.PORT);
-
Ejemplo sencillo: Creando nuestros eventos
var eventos = require('events');
var EmisorEventos = eventos.EventEmitter;
var ee = new EmisorEventos();
ee.on('datos', function(fecha){
console.log(fecha);
});
setInterval(function(){
ee.emit('datos', Date.now());
}, 500);
- Ejemplo: Juguemos al Ping-Pong
var EventEmitter = require('events').EventEmitter;
var pingPong = new EventEmitter();
var pingNumero = 1;
console.log('Bienvenido al juego de Ping/Pong!');
console.log('Empezamos en 5 segundos....');
setTimeout(function(){
console.log('Primer Ping... que desencadenará el juego');
pingPong.emit('ping', pingNumero);
pingNumero++;
}, 5000);
pingPong.on('ping', function(numero) {
console.log('Llegó el Ping('+numero+'). Emitimos Pong');
setTimeout(function(){
pingPong.emit('pong');
}, 1000);
});
pingPong.on('pong', function() {
console.log('Llegó el Pong. Emitimos Ping');
setTimeout(function(){
pingPong.emit('ping', pingNumero);
pingNumero++;
}, 1000);
});
var pingLogger = function(numero) {
console.log('Llegó el Ping ('+numero+') al nuevo listener');
}
setTimeout(function(){
console.log('Añadiendo un nuevo listener a Ping');
pingPong.on('ping', pingLogger);
}, 10000);
setTimeout(function(){
console.log('Eliminando el último listener');
pingPong.removeListener('ping', pingLogger);
}, 12000);
console.log('Nota: Recuerda que los Eventos nos ayudan con la asincronía, ¿no?');
Loop
Arquitecura diferente
1 - Crea las rutas básicas para tener una página web clásica (¿Quienes somos? | ¿Donde Estamos? | ¿Que hacemos? | Contacto... etc...)
var http = require('http'),
process = require('process'),
url = require('url');
http.createServer(function (req, res) {
var pathname = url.parse(req.url).pathname;
var hola = '<h1>Bienvenido!!</h1>';
if (pathname === '/') {
res.writeHead(200, {
'Content-Type': 'text/html'
});
res.end(hola);
} else if (pathname === '/quienes') {
res.writeHead(200, {
'Content-Type': 'text/html; charset=utf-8'
});
res.end(hola +'Somos una empresa que usa <b>la ñ y otros caracteres especiales! </b>....');
} else if (pathname === '/donde') {
res.writeHead(200, {
'Content-Type': 'text/plain; charset=utf-8'
});
res.end('Estamos cerca de tí....');
} else if (pathname === '/que') {
res.writeHead(200, {
'Content-Type': 'text/plain; charset=utf-8'
});
res.end('Hacemos cosas....');
} else if (pathname === '/bug') {
// Termina el proceso de Node
process.exit(1);
} else if (pathname === '/contacto') {
res.writeHead(200, {
'Content-Type': 'text/plain; charset=utf-8'
});
res.end('Contactanos!....');
} else {
res.writeHead(404, {
'Content-Type': 'text/plain'
});
res.end('L-E-G-E-N-D-A-R-I-O... 404!');
}
}).listen(process.env.PORT, process.env.IP);
console.log('Servidor funcionando en http://'+process.env.IP+':'+process.env.PORT+'/');
2 - Adaptamos el cajero para que funcione offline