Notas tomadas del video de fazt en
Es un entorno de ejecución de JavaScript
En la consola, colocamos el comando “node” para iniciar
Ctrl + LMath.random() * 10 // 1.3435211387340251
al igual de la consola del navegador, se utiliza LET, CONST, VAR
let x = 0 undefined
do { … x++; … console.log(x); … } … while (x < 10)
// 1 // 2 // 3 // 4 // 5 // 6 // 7 // 8 // 9 // 10
setInterval(()=>{console.log(‘hello’)}, 1000)
El REPL lo ejecuta cada 1 segundo infinitamente, para deteterlo presionamos dos veces CTRL + C
node -e “console.log(10 +10 )” // 20
Cambiar la carpeta con cd
Existe un comando .save que te permite guardar un archivo js en la carpeta donde estes ubicado
Si cerramos la sesion con CTRL C y volvemos a abrir una nueva sesion node, llamamos a la variable pero no regresará nada porque ees una sesion nueva, pero podemos cargar el archivo guardado con .load -nombre del archivo-
.load names.js
const names = ['joe', 'jhon', 'maria']
names
const newNames = names.map((name) => (`Hello ${name}`))
[ 'joe', 'jhon', 'maria' ]
>
En VsCode podemos ejecutar el archivo JS y ver la consola utilizando node
Nuestro archivo JS tiene este codigo
let userName = "fast";
let age = 17;
let hasHobbies = true;
let points = [10, 20, 30];
let user = {
name: "ryan",
lastName: "ray",
};
const PI = 3.1415;
if (age >= 18) {
console.log("tu eres un adulto");
} else {
console.log("No eres un adulto");
}
const names = ["jhon", "jon", "marco"];
for (let i = 0; i < names.length; i++) {
console.log(names[i]);
}
const showUserInfo = (userName, userAge) =>
`The username is ${userName}, the user is ${userAge} years old`;
console.log(showUserInfo("miguel", 30));
al llamar al archivo mediante node, este ejecutará todos los comandos que hayamos puesto en er archivo y los mostrar{a en consola
No eres un adulto
jhon
jon
marco
The username is miguel, the user is 30 years old
Node tiene multiples modulos para realizar operacione y funciones, ver documentacion
El modulo OS nos ayuda a entrar al sistema operativo del computador donde se está trabajando, por ejemplo:
os.userInfo() nos regresa un objeto con informacion del sistema, por ejempl el nombre del usuario o carpeta del usuario
os.uptime() nos regresa el tiempo que lleva encendida la maquina
os.plataform() se ve el sistema operativo donde se está ejecutando el node
os.totalmem() se ve la memoria total
os.freemem() regresa la memoria libre
os.release() regresa la informacion general del sistema
Este modulo nos permite trabajar co carpetas y archivos y poder saber sus direcciones.
Node se ejecuta en que sistema esta trabajando, asi que node usa este modulo para poder crear y entrar a los archivos y rutas de ubicacion
por ejemplo: en windows se entra a los archivos mediante
C:\Users\user\Desktop
en cambio en linux y Mac seria
home/user/desktop
este tipo dedetalles hay que tener en cuenta porque los proyectos se despliegan en serviores linux
const filePath = path.join('/public', 'dist', '/styles', 'main.css')
console.log(filePath) // \public\dist\styles\main.css
console.log(path.basename(filePath))
//main.css
console.log(path.dirname(filePath))
//\public\dist\styles
console.log(path.parse(filePath))
//{
// root: '\\',
// dir: '\\public\\dist\\styles',
// base: 'main.css',
// ext: '.css',
// name: 'main'
//}
console.log(path.resolve('dist'))
// C:\Users\57320\Desktop\Node-course\dist
El módulo node:fs permite interactuar con el sistema de archivos siguiendo el modelo de las funciones POSIX estándar.
se puede leer, modificar, agregar o eliminar archivos utilizando este modulo
const first = fs.readFileSync('./data/first.txt')
leerá el archivo y regresa un buffer
<Buffer 68 6f 6c 61 20 6d 75 6e 64 6f 20 64 65 73 64 65 20 65 6c 20 61 72 63 68 69 76 6f>
para poder leerlo con letras y palabras, añadimos un segundo parametro ‘Utf8’, quedando asi
const first = fs.readFileSync('./data/first.txt', 'Utf8')
//hola mundo desde el archivo
tambien se puede utilizar el metodo JS
console.log(first.toString())
Esta funcion recibe dos parametros, la ruta de ubicacion del archivo y el contenido que tendrá
fs.writeFileSync('./data/tercero.txt', 'este es un tercer archivo')
Utilizar file sistem con método asíncrono
1 Primer paso
fs.readFile('./data/first.txt', function(){
console.log('Terminó')
})
Esta fragmento de código le indica al CPU que ejecute primero la funcion de leer el archivo y luego que termine, va a ejecutar la siguiente funcion de mostrar el mensaje en colsola.
2 Segundo paso La segunda funcion regresa dos parametros, error y data, que indican que salio mal y que salio bien en la ejecución del codigo
fs.readFile('./data/first.txt', function(error, data){
console.log(error)
console.log(data)
})
Al ejecutarse de esta manera el codigo, mos regresa dos valores null y <Buffer 68 6f 6c 61 20 6d 75 6e 64 6f 20 64 65 73 64 65 20 65 6c 20 61 72 63 68 69 76 6f>, el primero es null ya que no existe nungun error que mostrar, el segundo es el texto del archivo fisrt.txt pero en codigo buffer, que deberá ser traducido con UTF-8
Otra manera de colocar el codigo anterior, es con arrow function, y colocando el .toString() para que traduzca el código buffer y funcionará perfectamente igual
fs.readFile('./data/first.txt', (error, data) => {
console.log(error)
console.log(data.toString())
})
})
3 Tercer paso No es necesario mostrar un error si no existe, asi que se mostrará con un condicional if
si colocamos un error a proposito
fs.readFile('./desconocida/first.txt', (error, data) => {
if (error){
console.log(error)
}
console.log(data.toString())
})
nos regresa el error
[Error: ENOENT: no such file or directory, open 'C:\Users\57320\Desktop\Node-course\desconocida\first.txt']
4 Si es necesario leer un archivo despues de leer el primero, se podria hacer de esta manera
fs.readFile('./data/first.txt', (error, data) => {
if (error){
console.log(error)
}
console.log(data.toString())
fs.readFile('./data/second.txt', (error, data) => {
if (error){
console.log(error)
}
console.log(data.toString())
fs.writeFile('./data/newFile.txt', 'archivo creado desde fs', (error, data)=> {
console.log(error)
console.log(data)
})
})
})
este codigo, lo que hace es ejecuta la primera funcion, lee el primero archivo, finalizado este lee el segundo archivo y luego finalizado crea un archivo con la tercera funcion, en la consola regresará
hola mundo desde el archivo
hello world 2
null
undefined
null es porque no existe un error en la tercera funcion y el undefided porque la funcion para crear archivos no regresa nada
Pero esta practica no es recomendable, porque si hay muchos fragmetos, se va iendo a la derecha y esto se llama callback hell, ese metodo es inmantenible, se evita con promesas y async/await
En este módulo nos va a servir para poder crear los principales progranas qye se usan en Node, que serian servidores web, para comenzar creamos un archivo llamado http.js, importamos el modulo y guardamos en una constante del mismo nombre
const http = require('http')
PAra comenzar a entender este modulo primero hay que explicar un concepto basico en aplixaciones web wue se conoce conmo cliente-servidor.
Protocolo HTTP, es la manera de comunicar de entre dos computadores, la del cliente y el servidor.
con el modulo HTTP ahora creamos un servidor
Un servidor es un programa que estará 24/7 recibienod y enviando información, como por el momento no es necesario enviar una respuesta a un cliente, solo colocamos un ‘Hello world’ como respuesta, node requiere que finalices la respuesta despues de obtener un response, asi que debemos finalizar con response.end(), cuando alguien visote nuestro servidor, solo se le regresará un texto que diga “Hello World”, luego necesitamos un puerto donde esté funcionando constantemente nuestro programa, para esto buscamos un puerto de la lista que hay en internet buscamdo uno que no esté reservado, para este ejemplo, usaremos el puerto 3000
const http = require('http')
http.createServer((request, response) => {
response.write('hello World')
response.end()
}).listen(3000)
console.log('Servidor escuchando en el puesrto 3000')
Al ejecutar nos regresará en consola Servidor escuchando en el puesrto 3000 y si visitamos localhost:3000 regresa un “Hello world”, ya esto nos indica que el puerto está funcionando
En la seccion anterior hemos creado un ejemplo basico de un servidor HTTP, ahora veremos que funciona el objeto request.
Para esto colocamos un console.log(request) dentro de nuestro codigo y ejecutamos, la pa gina de localhost seguira funcionando, y muestra el “Hello World” pero si vamos a la consola de NodeJs veremos todos el objeto HTTP, el objeto HTTP es informacion acerca del cliente que se puede utilizar en el backend.
El objeto HTTP es muy grande y hay ciertas cosas puntuales que necesitamos saber, por ejemplo, si quiero saber la url del cliente, utilizamos console.log(request.url), guadramos, cerramos y volvemos a abrir el servidor, nos regresará
/
/favicon.ico
el ‘/’ es porque el navegador interpreta la url base que se esta visitando, en este caso es http://localhost:3000/ y toma el / final, y el /favicon.ico es porque siempre el navegador le va a pedir al servidor un favicon para mostrar, cada vez que el cliente cambie de url cambiara el / en la consola, si el cliente entra en http://localhost:3000/profile la consola regresará /profile, esto se puede utilizar para mostrar mensajes o paginas personalizadas dependiendo de la pagina que visita el cliente, por ejemplo:
const http = require('http')
http.createServer((request, response) => {
console.log(request.url)
if (request.url === '/about'){
response.write('Acerca de')
response.end()
}
response.write('hello World')
response.end()
}).listen(3000)
console.log('Servidor escuchando en el puesrto 3000')
esta version del codigo evaluará si el cliente entró a la página /about y regresará Acerca de, guardamos, cerramos y volvemos a abrir el puerto. Al entrar en la oagin /about la consola nos regresará un error, esto debido a que el codigo tiene dos response.write(), asi que para solucionar este caso, debemos colocar un return antes del response.end() de la pagina ‘/about’ para que se salga del codigo cuando lo ejecute, cerramos y volvemos a abrir el puerto.
Colocando estas condicionales, podemos establecer que se le regresa al cliente dependiendo la url que visite, de esta manera:
const http = require('http')
http.createServer((request, response) => {
console.log(request.url)
if (request.url === '/about'){
response.write('Acerca de')
return response.end()
}
if (request.url === '/'){
response.write('Welcome to the server')
return response.end()
}
response.write('not found')
response.end()
}).listen(3000)
console.log('Servidor escuchando en el puesrto 3000')
Welcome to the serverAhora, no solo se le puede regresra un texto, sino tambien un HTML al cliente.
const http = require('http')
http.createServer((request, response) => {
console.log(request.url)
if (request.url === '/about'){
response.write('Acerca de')
return response.end()
}
if (request.url === '/'){
response.write('Welcome to the server')
return response.end()
}
response.write('<h1>Error 404</h1>')
response.end()
}).listen(3000)
console.log('Servidor escuchando en el puesrto 3000')
Esto regresará un error de not found o 404 al cliente si entra a una pagina web no registrada.
Si queremos colocar mucho mas texto, es bastante incomodo con conmillas simples, utilizamos los backticks para poder realizar saltos de linea y colocar mas codigo
const http = require('http')
http.createServer((request, response) => {
console.log(request.url)
if (request.url === '/about'){
response.write('Acerca de')
return response.end()
}
if (request.url === '/'){
response.write('Welcome to the server')
return response.end()
}
response.write(`
<h1>Error 404</h1>
<p>Esta pagina no se encuentra</p>
<a href='/'>Regresar a la pagina de inicio</a>
`)
response.end()
}).listen(3000)
console.log('Servidor escuchando en el puesrto 3000')
De esta manera creamos nuestro servidor basico con node.
Hasta ajora, hemos aprendido a crear nuestros propios modulos, como los de la carpeta Math, o importado los modulos que ofrece node, pero hay modulos que no son creaos por nosotros ni trae node predeterminado, estos son los oaquetes de terceros, creados por otros desarrolladores, en codigo open source.
En esta pagina se encuentran modulos JavaScript y Node que se pueden utilizar
desarrolladores de node utilizan muchos paquetes aqui plasmados, por ejemplo, si queremos darle color a los mensajes de consola, utilizariamos colors
Realicemos un ejemplo:
Creamos un archivo en la carpeta raiz llamado click.js y colocamos el siguiente codigo
console.log('hello world')
console.log('borgesmj.github.io')
console.log('google.com')
Ejecutamos y comprobamos que este funcionando correctamente node click.js
ahora si le queremos colocar colores:
1 Ejecutamos el comando npm install colors
Esto creará tres archivos package.json package-lock-json y node_modules
2 importamos la propiedad colors
const colors = require('colors')
3 Solo hay que colocar un ‘.’ al final del string y el módulo nos dara una serie de opciones para colocar en la consola
console.log('hello world'.bgGreen)
console.log('borgesmj.github.io'.bgBlue)
console.log('google.com'.rainbow)
Existe una manera de crear tu propio archivo package.json manualmente, y colocar los datos que necesitemos
ejecutamos el comandp npm init y comienza a ejecutar unas preguntas referente a nuestro proyecto.
1 Colocalmos el nombre del proyecto 2 Colocamos la version. Esta está identificada por un numero semver (semantic version), que tiene tres numeros (0.0.1), si le hacemos cambios muy pequeños a nuestra app, le cambiamos el tercer numero, de izquierda a derecha, si añadimos un cambio importante, pero que no afecta a la biblioteca se cambia el numero del medio, pero si se realiza un gran cambio que ya no es compatible con una version anterior, se cambia el primer numero. 3 Desccripcion 4 Archivo inicial, es el archivo que se va a iniciar cada vez que se inicie el programa, por defecto, node sugiere “index.js” 5 test comand 6 repositoio de git 7 Palabras claves 8 Autor 9 Licencia
Con este package.json podemos crear nuestros propios comandos en los scripts, por ejemplo, creamos un comando llamado “ejecutar”, al que le ponemos las instrucciones “node app.js”, ahora en la consola colocamos npm run ejecutar, esto funciona para aquellos programas que tienen muchos parametros.
Si cambiamos el comando “ejecutar” a “start”, podemos quitar el run y que quede npm start, pero esto solo aplica para el comando start.
Podemos añadir todos los comandos que sean necesarios para nuestro proyecto.
Con un proyecto pequeño, no hay problema tener que guardar y ejecutar el comando cada vez que haya cambios, pero cuando es un proyecto grande, con mucho codigo, es recomendable utilizar el modulo “nodemon”
npm i nodemon -D
el -D es para instalarlo en el modo de desarrollo, para que node sepa que no es necesario en el modo de produccion
Lo que hace nodemon es ver todos los cambios que se vayan realizando en el codigo, y realiza los cambios sin tener que volver a ejecutar el comando
Node buscará los modulos dentro de nuestra lista de dependencias en el archivo package.json, si no lo encuentra, lo buscará en la carpeta “node_modules” y si no lo encuentra, lo buscara en las dependecias instaladas globalmente en el computador.
Para instalar una dependecia global, utilizamos la flag -g cuando vayamos a instalar nodemos o cualquier otro modulo
Este comando nos sirve para ejecutar aplicaciones de consola que ya vienen instalado con npm.
La carpera /node_modules/.bin tiene todos los ejecutables contenidos del proyecto
una manera de ejecutar algun comando contenido en la carpeta .bin podria ser con el siguiente comando:
.\node_modules\.bin\nodemon index.js
Para que ejecute el archivo index.js, ya que nodemon está almacenado dentro de esta ruta de carpeta, asi se puede usar modulos que funcionan como CLI (Command Line Interface).
Si instalamos un modulo cualquiera, por ejemplo Cowsay, para ejecutarlo mediante un scripts colocariamos en el package.json
{
"dependencies": {
"colors": "^1.4.0",
"cowsay": "^1.5.0",
"nodemon": "^3.0.1"
},
"devDependencies": {
},
"scripts": {
"divaca": "cowsay hello world"
}
}
Al ejecutarlo con npm run divaca la consola regresa
_____________
< hello world >
-------------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
Ahora imaginemos que no necesitemos instalar este modulo, porque es algo muy momentaneo y puntual, hay una manera de utilizarlo sin tener que instalarlo, y esta manera es con npx, npx buscara en internet un modulo que no existe en el computador, lo va a descargar y ejecutarlo inmediatamente
npx cowsay curso de node
La consola preguntará si procede a instalar el paquete, y luego ejecutará
_______________
< curso de node >
---------------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
¿Para que sirve esto? Hay veces que queremos ejecutar programas que esten desarrollados con Node, pero no queremos instalarlos, solo utlizarlos una sola vez y que liego se elimine.
Veamos otro ejemplo:
1 Creemos una carpeta “public” y dentro de esta carpeta creamos un archivo HTML
2 Crearemos un servidor temporal utilizando el paquete npm serve, pero no lo instalaremos por completo, ya que no lo necesitamos para desarrollo ni para produccion, asi que utilizaremos el comando npx
3 En la consola colocamos
npx serve public
nos crea un servidor http, y lo interesante de esto, es que los cambios que se realicen en el archivo html se veran reflejados en la pagina web.
Hasta este momento hemos creado funciones que nos permiten poder manejar peticiones, funciones que nos permiten poder ser ejecutadas despues de un tiempo, un ejemplo de esto es que podemos crear un servidor basico utilizando el modulo HTTP.
Este modulo, para poder crearlo, utiliza una funcion createServer y como parametros esperaba otras funciones, lo interesante de JavaScript es que vamos a necesitar una funcion, porque los parametros se ejecutan despues de un tiempo, o mejor dicho, se ejecutan despues de un evento. Para poder entender porque se ejecuta una funcion dentro de una funcion, hay que entender el concepto basico de node que se conoce como event loop.
Aqui tenemos un ejemplo
1 Creamos un archivo event_loop.js que tendrá tres comandos sencillos
console.log('first')
console.log('second')
console.log('third')
y ejecutamos el comando node event_loop.js la consola nos regresa:
first
second
third
2 Cuando halbamos de JavaScript y el Codigo asincrono
console.log('first')
setTimeout(() => {
console.log('second')
}, 3000);
console.log('third')
node ejecutará el primer y tercer console.log, y el segundo lo ejecutara despues de un tiempo
Aunque cambiemos el valor del tiempo a 0, de esta manera
console.log('first')
setTimeout(() => {
console.log('second')
}, 0);
console.log('third')
la consola regresará
first
third
second
por mas que el tiempo sea 0, node interpreta ese fragmento de codigo como una tarea pendiente y lo ejecuta al final.
Para hacer un ejemplo mas visual, crearemos un servidor HTTP sencillo
const http = require("http");
const server = http.createServer((req, res) => {
if (req.url === "/") {
res.write("welcome to the server");
return res.end();
}
if (req.url === '/about'){
return res.end('this is about page') // esta es otra manera de escribir, sin tener que colocar 'res.write'
}
res.end('not found')
});
server.listen(3000)
console.log('server on port 3000')
Ahora, aqui esta el detalle de que node puede manejar una sola tarea a la vez, supongamos que cuando se visita la pagina /about vamos a estar trabajando con una logica pesada, consulta a una base de datos o a otro servidor, o la ejecucion de una tarea que lleve mucho tiempo, por ejemplo:
const http = require("http");
const server = http.createServer((req, res) => {
if (req.url === "/") {
res.write("welcome to the server");
return res.end();
}
if (req.url === '/about'){
// una tarea pesada
for (let i = 0; i < 100000; i++) {
console.log(Math.random() * i)
}
return res.end('this is about page') // esta es otra manera de escribir, sin tener que colocar 'res.write'
}
res.end('not found')
});
server.listen(3000)
console.log('server on port 3000')
va a estar cargando la pagina about hasta que realice toda la tarea, incluso si visitamos en otra pestaña localhost:3000 no cargará porque la base de la url esta bloqueado mientras realiza la tarea, no permite que node realice otra tarea, al bucle for se le conoce como codigo bloqueante, para evitar esto, se utiliza codigo asincrono, se ejecuta en un segundo plano, asi el codigo seguira ejecutando, y recibiendo peticiones
En esta seccion aprenderemos a utilizar un concepto muy importante de JS que se le conoce como promesas, es una manera mas facil de escribir codigo asincrono y ,ejor entendible que los callback.
Para entender este problema, resolveremos el codigo de file sistem utilizando promesas:
1 Crearemos un archivo que llamaremos promises.js y dentro de promises vamos a tratar de leer un archivo
const {readFile} = require('fs')
readFile('./data/first.txt', 'utf-8', (err, data) => {
if (err){
console.log(err)
}
console.log(data)
})
nos regresa en la consola
hola mundo desde el archivo
El código funciona, pero escrito de esa manera, es un poco dificil de entenderm sobre todo para proyetos grandes, asi que se puede convertir el callback en una promesa:
const {readFile} = require('fs')
function getText(pathFile){
return new Promise(function(resolve, reject){
readFile(pathFile, 'utf-8', (err, data) => {
if (err){
reject(err)
}
resolve(data)
})
})
}
// si quiero leer un archivo, ya no es necesario escribir "readfile", en cambio, llamamos a la funcion pasando la ruta del archivo como parametro
getText("./data/second.txt")
.then((result) => console.log(result))
//si quiero leer otro archivo despues del primero
.then(() => getText("./data/tercero.txt"))
.then(result => console.log(result))
.catch((error) => console.log(error))
puedo tener tantos .then como sean necesarios pero solo es necesario un .catch(error), pero hay una manera aun mas sencilla de escribir este código.
Hay una manera mas sencilla de escirbir el codigo anterior, utilizando un concepto nuevo de JavaScript, el cual se llama “Async/Await”
Async sirve para que podamos especificar que una funcion adentro de su contenido, está manejando un codigo asincrono, y await es cuando estamos usando una funcion asincrona, para indicar que esa funcion va a tomar algo de tiempo.
Volveremos a utilizar la funcion getText() pero con async/await
const {readFile} = require('fs')
function getText(pathFile){
return new Promise(function(resolve, reject){
readFile(pathFile, 'utf-8', (err, data) => {
if (err){
reject(err)
}
resolve(data)
})
})
}
async function read(){
const result = await getText('./data/first.txt')
const result2 = await getText('./data/second.txt')
const result3 = await getText('./data/tercero.txt')
const result4 = await getText('./data/newfile.txt')
console.log(result)
console.log(result2)
console.log(result3)
console.log(result4)
}
read()
pero ahora si queremos que nos refleje el error en caso de que haya uno, utilizamos try/catch
const { error } = require("console");
const { readFile } = require("fs");
function getText(pathFile) {
return new Promise(function (resolve, reject) {
readFile(pathFile, "utf-8", (err, data) => {
if (err) {
reject(err);
}
resolve(data);
});
});
}
async function read() {
try {
const result = await getText("./data/first.txt");
const result2 = await getText("./data/second.txt");
const result3 = await getText("./data/tercero.txt");
const result4 = await getText("./data/newfile.txt");
console.log(result);
console.log(result2);
console.log(result3);
console.log(result4);
} catch (error) {
console.log(error);
}
}
read();
Pero tambien podemos generar y explicar nuestros propios errores para indicar a otros desarrolladores donde está. utilizamos throw
En la seccion anterior hemos aprendido a como escribir promesas de una manera bastante sencilla con async/await, pero una parte importante es hacer callbacks y el fragmento de getText() es bastante dificil de leer, para hacerlo mas sencillo, node tiene modulos para hacerlo mas sencilla.
toda la funcion function getText(pathFile) lo pasamos a una sola linea const readFilePromise = promisify(readFile) quedando de esta manera:
const { readFile } = require("fs");
//importamos promosify desde los modulos de node
const { promisify } = require("util");
const readFilePromise = promisify(readFile);
async function read() {
try {
const result = await readFilePromise("./data/first.txt", "utf-8");
console.log(result);
const result2 = await readFilePromise("./data/second.txt", "utf-8");
console.log(result2);
const result3 = await readFilePromise("./data/tercero.txt", "utf-8");
console.log(result3);
const result4 = await readFilePromise("./data/newfile.txt", "utf-8");
console.log(result4);
} catch (error) {
console.log(error);
}
}
read();
Desde file sistem podemos ahorrar el convertir la promesa con promisify utilizando const { readFile } = require('fs/promises'); quedando de la siguiente manera:
const { readFile } = require('fs/promises');
async function read() {
try {
const result = await readFile("./data/first.txt", "utf-8");
console.log(result);
const result2 = await readFile("./data/second.txt", "utf-8");
console.log(result2);
const result3 = await readFile("./data/tercero.txt", "utf-8");
console.log(result3);
const result4 = await readFile("./data/newfile.txt", "utf-8");
console.log(result4);
} catch (error) {
console.log(error);
}
}
read();
Así, de esta manera, nos hemos ahorrado otras lineas de codigo, haciendolo mas entendible y facil de leer
En esta sección vamos a aprender a manejar eventos en Node
Cuando trabajamos con JavaScript en en frontEnd, hemos visto que si queremos añadir una escucha a un boton, debemos añadir un boton en el HTML, un script al documento, y un addEventListener a ese boton.
Una parte importante de JavaScript es el manejo de eventos.
Node provee modulos para crear eventos propios
const EventEmitter = require('events')
const customEmitter = new EventEmitter()
/*
customEmitter.emit() //emitir un evento
customEmitter.on() // escucha el evento
*/
customEmitter.on('response', (data) => {
console.log(data)
})
customEmitter.emit('response')
la consola nos regresa undefined ya que el response esperaba unos datos, pero si modificamos el evento ‘on’ a:
customEmitter.on('response', (data) => {
console.log('recibido')
console.log(data)
})
nos regresará recibido y undefined
Ahora si colocamos otro parametro en customEvent.emit() de esta manera
customEmitter.emit('response', 'hello world')
la consola nos regresará
recibido
hello world
Asi como en el HTML podemos poner multiples eventos, podemos colocar multiples emit
customEmitter.emit('response', 'hello world')
customEmitter.emit('response', 'borgesmj')
customEmitter.emit('response', 'nodejs')
customEmitter.emit('response', 30)
customEmitter.emit('response', [1,2,3])
La consola nos regresará
recibido
hello world
recibido
borgesmj
recibido
nodejs
recibido
30
recibido
[ 1, 2, 3 ]
¿Para que sirve estos eventos?
Si recordamos, cuando creamos nuestro modulo HTTP, hemos creado un servidor, ese servidor espera una funcion, y esa funcion responde despues de determinado evento, es decir, cuando llega una peticion recien se ejecuta ese evento, y la funcion createServer tiene multiples lineas de escucha y emision de eventos.
Los streams nos ayuda a enviar o dividir un archivo grande en multiples partes, para que sea trasmitido facilmente.
Primero creamos un archivo grande
const {writeFile} = require('fs/promises')
const createBigfile = async() => {
await writeFile('./data/bigfile.txt', 'hello world'.repeat(1000000))
}
createBigfile()
El .repeat() repetirá las veces que tenga de parámetro
para ver el tamaño del archivo colocamos el comando dir data y, en este caso, nos regresa:
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 3/11/2023 1:45 p. m. 11000000 bigfile.txt
-a--- 30/10/2023 2:03 p. m. 27 first.txt
-a--- 2/11/2023 9:43 a. m. 23 newFile.txt
-a--- 30/10/2023 2:00 p. m. 13 second.txt
-a--- 30/10/2023 2:45 p. m. 50 tercero.txt
El archivo bigfile pesa mas de 10Mb, si un usuario desea usar este archivo, la mejor opcion seria dividirlo en partes
const {createReadStream} = require('fs')
const streams = createReadStream('./data/bigfile.txt')
streams.on('data', (chunk) => {
console.log(chunk)
})
Requerimos createReadStream del modulo fs, y lo llevamos a una constante y le pasamos de parametro el archivo grande, luego colocamos un listener de evento, nos regresa un objeto de eventos, luego cuando escucha el ebvento data, nosotros veremos porciones de datos a los que llamamos chunk, dividirá el archivo 65kb a la vez, y eso es lo que va mostrando.
Aparte de dividir los archivos, tambien tiene el evento para enviar un mensaje al final del stream
streams.on('end', () => {
console.log('ya termine de leer el archivo')
})
y el createReadStream puede recibir un objeto de parametro donde se puede colocar el codificado
const streams = createReadStream('./data/bigfile2.txt',{
encoding: 'utf-8'
})
const http = require('http')
const {createReadStream} = require('fs')
const server = http.createServer((req, res) => {
const fileStream = createReadStream('./data/bigfile.txt', {
encoding: 'utf-8'
})
fileStream.on('data', (chunk) => {
fileStream.pipe(res)
})
fileStream.on('error', error => {
console.log(error)
})
})
server.listen(3000)
console.log(`server on port ${3000}`)
Este es un modulo que permite importar módulos en otros módulos.
Ya antes hemos hablado de los modulos, que nos funcionan para poder dividir un proyecto en partes, y teniamos la sintaxis module.exports, a esta sintaxis se le conoce como Commom JS, para poder exportar e importar modulos.
Actualmente, hay un estandar en el navegador, y Node tambien está tratando de adaptarse a ese estandar, es decir, una sola forma de importar modulos. ¿Es posible usar import y export?, Si, si se puede usar, pero se debe realizar una configuracion antes.
Primero aprendamos una verison mas rapida de npm init para crear un package.json
Introducimos el comando
npm init -y
De esta manera, se crea el archivo con las respuestas predeterminadas o por defecto.
Se hace énfasis en el package.json debido a que la configuracion va en este archivo
Añadimos una propiedad llamada "type": "module",, ahora podemos usar la sintaxis import y export en los archivos de JavaScript
creamos un archivo esmodule.js, recordemos que teniamos un archivo llamado index.js dentro de la carpeta Math que esportaba de esta manera:
module.exports = {
add,
sustract,
divide,
multiply
}
Ahora podemos hacerlo de esta manera:
export default {
add,
sustract,
divide,
multiply
}
de la manera ES6, y en el archivo que acabamos de crear lo importaremos
import math from './Math/index.js'
Muy imortante: debe tener la extension del archivo.
Otro dato importante, el archivo que se exporta no debe quedarse con module.exports = debe tener export default, ya que la primera manera es commonJs y es la manera vieja y la segunda manera es mas moderna y que mas se asemeja a la usada por el navegador, se puede usar o una o la otra, pero no ambas al mismo tiempo.
Supongamos que no queremos exportar todas las funciones del archivo, sino funciones individualmente
export function add(x,y){
return x+y
}
export function sustract(x,y){
return x-y
}
function multiply(x,y){
return x*y
}
function divide(x,y){
return x/y
}
y en archivo donde importamos
import {sustract} from './Math/index.js'
console.log(sustract(10,20))
En la seccion anterior hemos aprendido a utilizar los modulos de ES6, otra forma de conocer otras caracteristicas de node, es conociendo las API modernas que tiene, por ejemplo, utilizamos una API muy utilizada en las ultimas versiones, que seria fetch(), esta API nos sirve para traer datos de una direccion o una url.
Para el ejemplo, estaremos trabajando emn el archivo fetch.js
fetch("https://jsonplaceholder.typicode.com/posts")
.then(res => res.json())
.then(data => console.log(data));
Y si lo queremos utilizar con una funcion asincrona
async function loadData() {
try {
const res = await fetch("https://jsonplaceholder.typicode.com/posts");
const data = await res.json();
console.log(data);
} catch (error) {
console.log(error)
}
}
loadData()
Hasta ahora hemos aprendido las bases de Node, hemos aprendido conceptos como los eventos, FS, y demas modulos, ahora si revisamos el modulo de http, hemos estado colocando logica como request.url === '/ y regresabamos algo, esto funciona, pero si debemos construir una aplicacion real, por ejemplo con muchas mas rutas, ese metodo seria muy laborioso, en la actualidad se no se escribe codigo desde cero, para eso ya estan construidos los framworks que nos permiten resumir las logicas.
Para ejemplo, utilizaremos uno de esos frameworks
Vamos a crear una carpeta nueva en el escritorio y la llaaremos node-website
Comenzamos con iniciar el proyecto npm init -y, esto nos creará el package.json del proyecto
Ahora instalaremos una framework para trabajar en el proyecto
Googleamos “nodejs frameworks list” y nos da una serie de frameworks utilizados en la actualidad, para este ejemplo se utlizará ExpressJs que lo conseguimos en el siguiente enlace
¿Que hace este framework?, nos permite escribir codigo de backend similar a lo que hemos hecho hasta ahora, sin condicionales y minimizando el código.
Comenzamos con instalarlo, npm i express y creamos el archivo de arranque ìndex.js dentro del cual colocamos
import express from "express";
const app = express()
app.listen(3000)
NOTA: recuerda modificar el package.json para y colocar "type": "module",
Si visitamos el enlace http://localhost:3000/ nos regresa un Cannot GET \ que seria la respuesta por defecto y la muestra que nuestro programa funcionó bien pero que no regresa nada, si quisieramos regresar algo colocamos mas funciones
import express from "express";
const app = express()
app.get('/', (req, res) => {
res.send('<h1>Bienvenido</h1>')
})
app.get('/about', (req, res) => {
res.send('<h1>about</h1>')
})
app.listen(3000)
console.log('server on port 3000')
En esta seccion, desplegaremos una aplicacion de Node de forma gratuita y aprenderemos como se ve una aplicacion de node en la realidad
Cuando realizamos aplicaciones con Node, nosotros no solo elaborar herramientas basadas en JavaScript que interactuan con el sistema operativo, sino que su principal uso es crear servidores web.
En la seccion anterior creamos una mini app ejemplo utilizando la framework Express, ahora, nosotros necesitamos desplegarlo, subirlo a la internet, ahora en este momento, nosotros podemos trabajar con node porque lo tenemos instalado en nuestro ordenador, por lo tanto, tambien debe estar instalado en donde se requiera trabajar.
Uno de los servicios gratuitos y en la nube para poder subir el codigo es Heroku,