- Desarrollo de librerías isomórficas
- Integración de clientes y plataformas de mensajería (Slack, Hangouts, Telegram...)
- Trabajando con otros lenguajes de programación desde Node.js (Python, Bash, etc..)
- Creación de aplicaciones CLI
- Reusabilidad
- Gestión de la información
- Soporte multiplataforma
- Gestión de tareas periódicas
- Trabajando con fechas CRON
- Scheduled
- Scraping
- Librerías propias de Node.js como «X-Ray», «Cheerio», etc...
- Integración de librerías de otros lenguajes como «Beautiful Soup» de Python
- Internet of Things (IoT) y Robótica
- Trabajando con comunicación serial (USB, Bluetooth)
- Arduino y su ecosistema
- Sensores (potenciómetros, lumínicos, sonoros, proximidad…)
- Actuadores (motores, leds, servos…)
- Trabajando desde Node.js con librerías como Johnny-Five, Cyclon.js…
- Otras formas de trabajar con la electrónica
- Creación de Apps híbridas con PhoneGap y Apache Cordova
- Creación de aplicaciones HTML5 de escritorio (Electron, Photon, etc...)
Imprescindibles para este proyecto:
- Web Backend (Rutas Backend, Nodejs y/o Cloud functions)
- Web Frontend (Ajax, HTML5 Apis, rutas front, etc...)
- Scraping
- Uso de patrones
No críticos pero puntuables para este proyecto:
- Versión de escritorio
- Version App Hibrida
- Integración con IOT
- Version CLI
Extras:
- Testing
- JSDocs
- Gestión del proyecto desde el inicio en un repositorio propio en Github
- Firebase u otra base de datos
- WebSockets
- Sin frameworks ni librerias externas en la medida de lo posible
Fecha de entrega:
- Septiembre 2018
-
- 1 - Uncaught Fatal Exception - No ha podido ser capturada
- 2 - Unused (reserved by Bash for builtin misuse)
- 3 - *Internal JavaScript Parse Error *
- 4 - *Internal JavaScript Evaluation Failure *
- 5 - Fatal Error - There was a fatal unrecoverable error in V8.
- 6 - Non-function Internal Exception Handler
- 7 - Internal Exception Handler Run-Time Failure
- 8 - Unused
- 9 - Invalid Argument
- 10 - *Internal JavaScript Run-Time Failure *
- 12 - Invalid Debug Argument
- 128 - Signal Exits - El sistema operativo acaba con Node.
-
process.argv:
console.log(process.argv)
/*
1. ubicacion de node (bin)
2. ubicación del script (location)
3. [Otros parametros]
*/
- Detalles del sistema
process.argv[2] = process.argv[2] || "Node.js funcionando desde C9.io";
console.log("===================================");
console.log("Id: " + process.pid);
console.log("Título: " + process.title);
console.log("Ruta: " + process.execPath);
console.log("Directorio Actual: " + process.cwd());
console.log("Node Versión: " + process.version);
console.log("Plataforma: " + process.platform);
console.log("Arquitectura: " + process.arch);
console.log("Tiempo activo: " + process.uptime());
console.log("Versiones Dependencias: ");
process.argv.forEach((val, index, array) => {
console.log(`${index}: ${val}`);
});
console.log("===================================");
- console.log("Hola"):
var mensaje = "Hola"
process.stdout.write(mensaje + '\n')
Captura de errores inesperados
process.on('uncaughtException', function (err) {
console.error(error.stack);
});
- Es interesante almacenar estos errores o enviarlos por email.
- Estos errores se escapan del sistema convencional de errores.
Ejecucción de tareas antes de la finalización del proceso
process.on('exit', function (err) {
// Limpiar cache.. y cosas similares...
});
Captura de señales en entronos UNIX
// SIGINT -> Control-C
process.stdin.resume(); // Evitamos que se cierre Node.js
process.on('SIGINT', function() {
console.log('Llegó SIGINT. Control-C... Saliendo...');
process.exit(0);
});
-
Solo para entornos UNIX
-
Necesitamos shebang
#!/usr/bin/env node
console.log('Soy un script!');
- Necesitamos hacer el script ejecutable
chmod +x mi_escript_archivo.js
- Ejecutando el script
./mi_escript_archivo.js <parámetro>
Ejemplo: hola
#!/usr/bin/env node
console.log("hola");
process.exit(1);
Arrancar Scripts al incio del sistema
- Librerías:
-
Ideal para tareas pesadas, inestables o muy lentas
-
Nos permite usar comandos del sistema.
-
Podemos lanzar aplicaciones basadas en otros lenguajes o sistemas.
-
Creando hijos y usando spawn
-
spawn devuelve un stream
var spawn = require('child_process').spawn;
var ping = spawn('ping', ['fictizia.com']);
ping.stdout.setEncoding('utf8');
ping.stdout.on('data', function (data) {
console.log(data);
});
- Creando hijos y usando exec
- exec retorna un buffer
var exec = require('child_process').exec
// cat solo funciona en UNIX
exec('cat texto.txt', function (err, stdout, stderr) {
if(!err){
console.log('El contenido de nuestro archivo', stdout)
} else {
console.log('Error: '+err)
}
})
- Manejando hijos:
var spawn = require('child_process').spawn
if(process.argv[2] === 'hijo'){
console.log('Estoy dentro del proceso hijo');
} else {
var hijo = spawn(process.execPath, [__filename, 'hijo'])
hijo.stdout.pipe(process.stdout)
}
- Manejando hijos (con heréncia):
var spawn = require('child_process').spawn
if(process.argv[2] === 'hijo'){
console.log('Estoy dentro del proceso hijo');
} else {
var hijo = spawn(process.execPath, [__filename, 'hijo'], {
stdio: 'inherit'
})
}
- Manejando hijos (contexto común):
var spawn = require('child_process').spawn;
var contador = 0;
contador += 1;
if(process.argv[2] === 'hijo'){
console.log('hijo', contador);
contador++;
console.log('pero.. además el hijo.. suma otra! y son', contador);
} else {
var hijo = spawn(process.execPath, [__filename, 'hijo'], {
stdio: 'inherit'
});
console.log('padre', contador);
}
- Sin usar Cluster
var http = require('http');
var url = require('url');
var server = http.createServer().listen(process.env.PORT);
server.on('request', function (req, res) {
var pathname = url.parse(req.url).pathname;
if (pathname === '/matame') {
res.writeHead(200, {
'Content-Type': 'text/plain'
});
res.end('Has matado el monohilo. PID: ' + process.pid);
process.exit(0);
} else {
res.writeHead(200, {
'Content-Type': 'text/plain'
});
res.end('Hola desde el monohilo. PID: ' + process.pid);
}
});
console.log('Servidor escuchando por el puerto ' +process.env.PORT);
- Usando Cluster.
- El proceso hijo que cae se vuelve a levantar.
- El proceso padre se mantiene "separado"
var cluster = require('cluster'),
http = require('http'),
url = require('url'),
cpus = require('os').cpus().length; // nproc
if (cluster.isMaster) {
console.log('Proceso maestro con PID:', process.pid);
for (var i = 0; i < cpus; i++) {
cluster.fork();
}
cluster.on('exit', function(worker) {
console.log('hijo con PID ' + worker.process.pid + ' muerto');
cluster.fork();
});
} else {
console.log('Arrancado hijo con PID:', process.pid);
var server = http.createServer().listen(process.env.PORT);
server.on('request', function (req, res) {
var pathname = url.parse(req.url).pathname;
if (pathname === '/matame') {
res.writeHead(200, {
'Content-Type': 'text/plain'
});
res.end('Has matado al proceso hijo ' + process.pid);
process.exit(0);
} else {
res.writeHead(200, {
'Content-Type': 'text/plain'
});
res.end('Hola desde ' + process.pid);
}
});
}
- Nos ofrece la posibilidad de alamacenar datos sin procesar
- Una vez iniciados no puede modificarse el tamaño
- Tamaño máximo 1GB
const buf1 = new Buffer(10); // buf1.length = 10
const buf2 = new Buffer([1,2,3]); // [01, 02, 03]
const buf3 = new Buffer('prueba'); // ASCII [74, 65, 73, 74]
const buf4 = new Buffer('ñam ñam', 'utf8'); // UTF8 [74, c3, a9, 73, 74]
console.log("===================================");
console.log("buf1: " + buf1.length);
console.log("buf2: " + buf2[0]);
console.log("buf3: " + buf3);
console.log("buf3 (hex): " + buf3.toString('hex'));
console.log("buf3 (base64): " + buf3.toString('base64'));
console.log("buf4: " + buf4);
console.log("buf4 (hex): " + buf4.toString('hex'));
console.log("buf4 (base64): " + buf4.toString('base64'));
console.log("===================================");
-
Gestionamos el flujo de datos
-
Muy usados por librerías y modulos
-
Capa de abstracción para operaciones con datos
-
Lógica de tuberias (cadena de procesos)
-
Gestiona el buffer por si mismo
-
Tipos:
- Redeable Lectura
- Eventos (data, error, end)
- Writable Escritura
- Eventos (drain, error, finish)
- Duplex Ambos
- Transform Transformación de datos
- PassThrough No manipula, solo manipula
- Redeable Lectura
-
Función .pipe()
- Simple:
origen.pipe(destino);
- Concatenando:
origen.pipe(destino).pipe(otroDestino);
- Simple:
-
Ejemplo: Stream multimédia
var http = require('http'),
fs = require('fs');
http.createServer(function(req, res) {
var cancion = 'cancion.mp3';
var stat = fs.statSync(cancion);
res.writeHead(200, {
'Content-Type': 'audio/mpeg',
'Content-Length': stat.size
});
var readableStream = fs.createReadStream(cancion);
readableStream.pipe(res);
}).listen(process.env.PORT);
- Stream y ficheros
var fs = require('fs');
var lectura = fs.createReadStream('archivo1.txt');
var escritura = fs.createWriteStream('otroArchivo.txt');
lectura.pipe(escritura);
-
Conocer todas las variables disponibles en el entorno
- Windows:
env
- UNIX:
SET
-
Guardar nuevas variables en el entorno
- Windows:
SET ALGO='mi secreto'
- UNIX:
export ALGO='mi secreto'
-
Recuperar las variables con Node.js
var datoRecuperado = process.env.ALGO; console.log(process.env.ALGO);
-
Creando variables del entorno limitadas a Node.js y temporales (SOLO UNIX)
- Arrancando...
NODE_ENV=production node app.js
- Usando datos...
if(process.env.NODE_ENV === "production"){ console.log("Entramos en modo producción"); } else if (process.env.NODE_ENV === "development"){ console.log("Entramos en modo desarrollo"); } else { console.log("Entramos en modo desconocido. ¡Revisa las variables del entorno!"); }
-
Alternativas
- Especificación de CommonJS
- Exports es un objeto que vamos "rellenando"
- La asignacion al exports es inmediata. No se pueden usar callbacks o similares
- No es necesario usar module.exports ya es que es global.
var exports = module.exports = {};
- Es importante controlar la reasignación de module.exports
- Exportar los datos:
// archivo -> config.js
var datoPrivado = "Lo que pasa en Node... se queda en Node";
var datoCompartido = "Hola! desde Config.js"
function privada (){
return datoPrivado;
}
exports.metodo = function () {
console.log(datoCompartido);
console.log(privada());
}
exports.mensaje = datoCompartido;
- Importar los datos:
var config = require('./config');
config.metodo();
console.log(config.mensaje);
- Exportar los datos:
// archivo -> config.js
var config = {
token: "<--- MiSecreto--->",
};
module.exports = config;
- Importar los datos:
var config = require('./config');
console.log(config.token);