Skip to content

seppo0010/promises-js-explanation

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

6 Commits
 
 

Repository files navigation

Promises js explanation

Creative Commons License

This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.

Una función puede devolver un valor

function sumar(v1, v2) {
    return v1 + v2
}
console.log(sumar(1, 2))

A veces obtener ese valor tarda tiempo. Por ejemplo si dependemos de una conexión a un servidor. Entonces en ese caso se proveía un callback para ser llamado cuando terminaba.

require('https').get('https://www.google.com.ar/', function(res) {
    console.log(res.statusCode)
})

Esto funciona, pero tiene varios problemas. Por un lado, si queremos hacer más de una cosa cuando termina tenemos que hacer una función que conozca todo lo que hay que hacer. También si hay que hacer varias cosas en serie queda una como callback de otra como callback de otra y el código se hace difícil de leer.

Entonces ahí nace el concepto de Promesa. La Promesa representa una promesa de un valor futuro. Es decir que la operación no te devuelve el valor que querés sino un objeto que eventualmente tendrá ese valor.

Una implementación simplificada de Promise es algo así:

var https = {
    get: function(url) {
        var promise = {
            resolved: false,
            value: null,
            callbacks: [],
            resolve: function(value) {
                this.value = value
                this.resolved = true
                for (var i = 0; i < this.callbacks.length; i++) {
                    this.callbacks[i](value)
                }
            },
            then: function(callback) {
                if (this.resolved) {
                    callback(this.value)
                } else {
                    this.callbacks.push(callback)
                }
            }
        }
        require('https').get(url, function(res) {
            promise.resolve(res)
        })
        return promise
    }
}
var promise = https.get('https://www.google.com.ar/')
promise.then(function(res) {
    console.log(res.statusCode)
})
promise.then(function(res) {
    console.log(res.headers['content-type'])
})

Promise fue agregado a Javascript por lo que no hay que hacer todo eso. Una función puede crear una promesa. Al hacerlo recibe dos funciones, una para llamar cuando tiene éxito y una para llamar cuando falla. Quien espera el valor puede agregar callbacks al éxito con then y al fallo con catch

const get = function(url) {
  return new Promise((resolve, reject) => {
    const lib = url.startsWith('https') ? require('https') : require('http');
    const request = lib.get(url, (response) => {
      if (response.statusCode < 200 || response.statusCode > 299) {
        return reject(response);
      }
      resolve(response)
    });
    request.on('error', (err) => reject(err))
  })
};


function run() {
  get('https://www.google.com.ar/')
    .then((res) => console.log(res.statusCode))
    .catch((err) => console.error(err));
}
run()

Las promesas se pueden encadenar para que una se resuelva con el valor de una anterior.

const suma = function(a, b) {
  return new Promise((resolve, reject) => { resolve(a+b) })
};

const resta = function(a, b) {
  return new Promise((resolve, reject) => { resolve(a-b) })
};

function run() {
  suma(1, 2)
    .then((res) => {
      console.log('el resultado de la suma es', res)
      return resta(res, 5)
    })
    .then((res) => {
      console.log('el resultado de la resta es', res)
    })
}
run()

Esta sintaxis se puede hacer aún más linda con async y await. Esto fue agregado recientemente y puede no estar disponible en viejas plataformas.

const get = function(url) {
  return new Promise((resolve, reject) => {
    const lib = url.startsWith('https') ? require('https') : require('http');
    const request = lib.get(url, (response) => {
      if (response.statusCode < 200 || response.statusCode > 299) {
        return reject(response);
      }
      resolve(response)
    });
    request.on('error', (err) => reject(err))
  })
};

async function run() {
    try {
      const res = await get('https://www.google.com.ar/')
      console.log(res.statusCode)
    } catch (err) {
      console.error(err)
    }
}

run()

Este ejemplo hace exactamente lo mismo que el ejemplo anterior, pero usando la sintaxis nueva.

await traduce automáticamente el código que continúa como si fuese código a ser ejecutado en el then de la Promise.

Sólo se puede llamar a await dentro de una función marcada como async.

La función al ser async hace que su valor de retorno sea automáticamente una Promise, porque si hubo una llamada a await se necesita que ella hubiese concluido para tener su propio valor.

async function sumar(a, b) {
    return a+b
}
sumar(1, 2).then((res) => console.log(res))

También se pueden combinar varias Promise en una sola para esperar a que todas terminen.

async function sumar(a, b) {
    return a+b
}
async function restar(a, b) {
    return a-b
}
async function esperar(time) {
    return new Promise((resolve) => setTimeout(() => resolve(), time))
}
async function run() {
    const [suma, resta, _] = await Promise.all([sumar(1, 2), restar(1, 2), esperar(1)])
    console.log(suma, resta)
}
run()

Y encadenar cosas es más fácil con async/await!

const suma = async function(a, b) {
  return a+b
};

const resta = async function(a, b) {
  return a-b
};

async function run() {
  const res_suma = await suma(1, 2)
  console.log('el resultado de la suma es', res_suma)
  const res_resta = await resta(res_suma, 5)
  console.log('el resultado de la resta es', res_resta)
}
run()

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published