Synchronous Programming

Asynchronous​ Programming

El hilo principal será bloqueado hasta que la operación finalice.

const fs = require('fs');
const instructions = fs.readFileSync('instructions.txt');
//...

file read

db operation

send http request

No detiene el hilo principal mientras se resuelve la operación y el proceso finaliza.

const fs = require('fs');
fs.readFile('instructions.txt', function (err, content) {  
  if (err) throw err;

  const instructions = content;
  //...
})

Single-threaded (mono-hilo)

Event Loop

Responsable de programar operaciones asíncronas.

Node.js al ser single-threaded, abstrae la complejidad de lidiar con hilos y sincronizarlos.

  1. El cliente 1 hace una petición al servidor.

  2. El servidor inicia la carga de un archivo y pasa un callback para cuando termine.

  3. El cliente 2 hace una petición que se responde inmediatamente.

  4. El archivo carga y se da respuesta al cliente 1.

Evita el Callback Hell

function hell(callback){
  asyncFunction(function(err, result){
    if(err){
      callback(err);
    }
    else{
      asyncFunction(function(err, result){
        if(err){
          callback(err);
          return;
        }
        asyncFunction(function(err, result){
          asyncFunction(function(err, result){
            asyncFunction(function(err, result){
              asyncFunction(function(err, result){
                asyncFunction(function(err, result){
                  callback(err, result)
                });
              });
            });
          });
        });
      });
    }
  });
}

Pyramid of Doom

Promesas

Representa una operación que aún no se ha completado pero que se espera que sea resuelta en el futuro.

function getLevel(level) {
  var url = "https://www.webservice.com/api/levels/" + level;
  return new Promise((resolve, reject) => {
    request(url, (err, data) => {
      if(err){
        reject(err);
      }
      else{
        resolve(data);
      }
    })
  })
}
getLevel(1).then(function(levelOne){
  console.log(levelOne);
  return getLevel(2);
})
.then(function(levelTwo){
  console.log(levelTwo);
  return getLevel(3);
})
.catch(function(err){
  console.log("Error: " + err.message);
});

Evita el Promise Hell

function getLevels(){
  return getConnection()
  .then(function(connection){
    return connectDatabase(connection);
  }).then(function(db){
    return db.Levels.getAll();
  }).then(function(levels){
    return JSON.parse(levels);
  });
}

getLevels()
.then((levels) => {
  var levelOne = levels[0];
})
.catch((err) => {
  throw err;
});
function getLevels(){
  return getConnection().then(function(connection){
    return connectDatabase(connection).then(function(db){
      return db.Levels.getAll().then(function(levels){
        return JSON.parse(levels);
      });
    });
  });
}

getLevels()
.then((levels) => {
  var levelOne = levels[0];
})
.catch((err) => {
  throw new Exception("Levels error: " + err.message);
});

Soportar Callbacks y Promesas

/*
 * @param {function(error, result)} cb - A callback to run.
 */
function getLevel(levelId, callback) {
    return new Promise((resolve, reject) => {
        request("https://www.midominio.com/api/levels/" + levelId, (err, data) => {
            if(err) {
                if(callback) { callback(err); }
                reject(err);
            }
            else{
                if(callback) { callback(null, result); }
                resolve(data);
            }
        })
    });
}

Módulos

Encapsulan código relacionado en una sola unidad de código.

var PI = Math.PI;

exports.area = function (r) {
  return PI * r * r;
};

exports.circumference = function (r) {
  return 2 * PI * r;
};
var circle = require('./circle.js');
console.log( 'El área de un círculo con radio 4 es '
           + circle.area(4));

circle.js

Servidor Web

const http = require('http');
const port = "8080";

const server = http.createServer((request, response) => {
  response.end('Hola Servidor Node.js!')
});

//Opcional para configurar puerto distinto al 80 (Default)
server.listen(port, (err) => {  
  if (err) {
    return console.log('Error:', err)
  }

  console.log(`Servidor escuchando en ${port}`)
})

index.js

node index.js

ó

npm init

npm install <modulo>

Configurar proyecto:

Instalar dependencias:

Ejecutar servidor:

npm start

HTTP verbs

GET, POST, PUT, DELETE, OPTIONS, ...

Soporta CORS?

HTTP request

Request

  • Headers: Contienen información como el tipo de explorador usado para ingresar a la página, claves de autenticación, formato de datos enviado (content-type, url-encoded, etc).

  • URL: La url específica que se solicitó al servidor, contiene información acerca de qué recursos cargar o qué se quiere hacer con esa petición (query strings)

  • Body: Es el cuerpo del request, donde se manda cualquier información oculta, digamos subir una imagen, crear un registro en la base de datos (json)

Response

Contiene los mismos elementos que el request, además de:

 

La información de la respuesta se envía en el body y a través de los headers.

var server = require('http');

function requestHandler(request, response){
  console.log("Alguien se ha conectado");
  response.writeHead(200,{"Content-Type":"text/html"});
  response.write("<h1>El servidor funciona correctamente</h1>");
  response.end();
}

server.createServer(requestHandler).listen(8888);

Ejemplos

Crear un registro

var url = require('url');
var fs = require('fs');

var route = url.parse(request.url).pathname;
var registry = fs.createWriteStream('registry.txt',{'flags':'a'});
registry.write(route + '\n');
function route(handle, pathname, request, response){
  if(typeof handle[pathname] === 'function'){
    handle[pathname](request, response);
  }
  else{
    response.writeHead(404,{"Content-Type":"text/html"});
    response.write("404 Not found");
    response.end();
  }
}

exports.route = route;

Enrutador

Obteniendo la url, podemos llamar una función diferente con los parámetros. Puede ser un módulo diferente encargado de cumplir específicamente esa función.

Recursos

Referencias

Node.js

By J.D Nicholls

Node.js

A talk about Node.js

  • 3,229