Introducción al curso

1

¡Alto! Tenemos una nueva versión de este curso para ti

2

Bienvenidos al Curso de Fundamentos de JavaScript

3

Repositorio de este curso de fundamentos de JS

Primeros pasos en JavaScript

4

Variables

5

Variables: Strings

6

Variables: Números

7

Funciones

8

El alcance de las funciones

9

Objetos

10

Desestructurar objetos

11

Parámetros como referencia o como valor

12

Comparaciones en JavaScript

Estructuras de Control y Funciones

13

Condicionales

14

Funciones que retornan valores

15

Arrow functions

16

Estructuras repetitivas: for

17

Estructuras repetitivas: while

18

Estructuras repetitivas: do-while

19

Condicional múltiple: switch

Arrays

20

Introducción a arrays

21

Filtrar un array

22

Transformar un array

23

Reducir un array a un valor

Programación Orientada a Objetos en JavaScript

24

Cómo funcionan las clases en JavaScript

25

Modificando un prototipo

26

El contexto de las funciones: quién es this

27

La verdad oculta sobre las clases en JavaScript

28

Clases en JavaScript

Asincronismo

29

Funciones como parámetros

30

Cómo funciona el asincronismo en JavaScript

31

Cómo funciona el tiempo en JavaScript

32

¿Qué pasó con swapi.co?

33

Callbacks

34

Haciendo múltiples requests

35

Manejando el Orden y el Asincronismo en JavaScript

36

Manejo de errores con callbacks

37

Promesas

38

Promesas Encadenadas

39

Múltiples promesas en paralelo

40

Async-await: lo último en asincronismo

Juego de HTML

41

Comenzando el juego

42

Generando una secuencia de números

43

Iluminando la secuencia de colores

44

Obteniendo el input del usuario

45

Agregando la verificación del color elegido

46

Agregando los estados finales del juego

47

Conclusiones del curso

Complementos

48

Diferencias entre var, let y const

49

Memoización: ahorrando cómputo

50

¿Hace cuántos días naciste?

51

Funciones recursivas

52

Entiende los closures de JavaScript

53

Estructuras de datos inmutables

54

Cambiando de contexto al llamar a una función

55

¿Cuándo hace falta poner el punto y coma al final de la línea?

No tienes acceso a esta clase

¡Continúa aprendiendo! Únete y comienza a potenciar tu carrera

Promesas Encadenadas

38/55
Recursos

A diferencia de los callbacks en el CallbackHell, que terminan estando anidados unos dentro de otros, cuando se usan Promesas la ejecución de las llamadas no se hacen de manera anidada sino de manera encadenada, al mismo nivel una debajo de la otra, lo que hace que el código sea mucho más legible y mantenible.

Aportes 235

Preguntas 35

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad?

Resumen de la clase:
Encadenar Promesas

Encadenar promesas es mucho más limpio que con el método anterior.
Primero escribimos la invocación de la promesa con un arrow function:

obtenerPersonaje(1)
    .then( personaje => {
        console.log(personaje.name)
    })
    .catch(onError)

Al resolver esta promesa vamos a retornar otra promesa invocando dentro del .then nuevamente la función obtenerPersona() con el id del siguiente personaje:

obtenerPersonaje(1)
    .then( personaje => {
        console.log(personaje.name)
        return obtenerPersona(2)
    })
    .catch(onError)

Y para obtener los valores de esta promesa encadenamos otro .then y copiamos la función parámetro cambiando el valor del id.


obtenerPersonaje(1)                                                                                                                                                            
    .then( personaje1 => {
        console.log(personaje1.name)
        return obtenerPersona(2)
    })
    .then( personaje2 => {
        console.log(personaje2.name)
        return obtenerPersona(3)
    })
    .then( personaje3 => {
        console.log(personaje3.name)                                                                    
        return obtenerPersona(4)
    })
    .
    .
    .
    .catch(onError)

Ahora es mucho más legible y si cualquiera de estas promesas da un error funciona el mismo .catch para todos.

La recursividad es la clave, legible y fácil de usar

const API_URL = 'https://swapi.co/api/'
const PEOPLE = 'people/:id'

const OPTS = { crossDomain: true}

function obtenerPersonaje(id, cantidad){

	return new Promise((resolve, reject) =>{
		const url = `${API_URL}${PEOPLE.replace(':id',id)}`
		$.get(url, OPTS, function(data){
			resolve(data)
		})
		.fail(() =>	reject(id))
	})
	.then((personaje) => {
		console.log(`El personaje es ${personaje.name}`)
		if(cantidad > 1)
			return obtenerPersonaje(id+1, cantidad-1)
	})
	.catch((id) => console.log (`Sucedio un error al obtener el personaje ${id}`))

}

Y se llama así para ver 10 personajes y empezar con el primero

obtenerPersonaje(1, 10)

Una forma de hacerlo en jasvascript, con async await.

const API_URL_PEOPLE = 'https://swapi.co/api/people/'

async function personajes(idPersonaje){
    let id=idPersonaje
    let response = await fetch(API_URL_PEOPLE+id)
    let data = await response.json()
    let nombre = data.name
    return nombre
}

let tamanoArray = 10
let id = 1

async function run(id){
    while (id <= tamanoArray) {
        let personaje = await personajes(id)
        console.log ('El personaje es: ', personaje)
        id++
    }
}
run(id)

Y te imprime el siguiente resultado:
El personaje es: Luke Skywalker
El personaje es: C-3PO
El personaje es: R2-D2
El personaje es: Darth Vader
El personaje es: Leia Organa
El personaje es: Owen Lars
El personaje es: Beru Whitesun lars
El personaje es: R5-D4
El personaje es: Biggs Darklighter
El personaje es: Obi-Wan Kenobi

para abreviar el código podemos usar un ciclo, eso nos ahorra el copiar y pegar


const API_URL= 'https://swapi.co/api/'
var people_url= 'people/:id'

var URL= ''
const opts= { crossdomain: true}
function getCharacter(id, promise)
{
    return new Promise(function(resolve, reject)
    {
        URL= `${API_URL}${people_url.replace(':id', id)}`
        $.get(URL, opts, (data)=> resolve(data))
        .fail(() => reject(id))
    })
}
for(i= 1; i<= 5; i++)
{
    getCharacter(i)

    .then(function ({name}){
        console.log(`el personaje es ${name}`)
        return getCharacter(i+1)
    }).catch(()=>console.log('error 404 not found'))

}```

aquí les dejo documentación que me ayudó a entender más sobre las promesas y cómo encadenarlas
https://developer.mozilla.org/es/docs/Web/JavaScript/Guide/Usar_promesas#Encadenamiento

En el blog de platzi encontré este artículo, que ayuda a entender mejor que son y cómo funcionan la promesas en Javascript: https://platzi.com/blog/que-es-y-como-funcionan-las-promesas-en-javascript/

ya quede loco, la verdad no entiendo nada de asincronismo ¿de pronto alguna sugerencia para aprenderlo de manera mas sencilla?

los metodos .then & .catch son como un if & else, ahora si logre entender las promesas tienen un constructor con los parámetros “resolve & reject” y despues sus metodos que funcionan a modo de posibles condicionales

Código de la clase en Vanilla JS por si lo desean analizar:

//const urlApi = 'https://swapi.dev/api/';
//const character = 'people/:id';
const urlApi = 'https://rickandmortyapi.com/api/character/'
const character = ':id';

function getData(id){    
    //La promesa se debe definir antes de la estructura request de la funcion
    return new Promise(function(resolve, reject){
        var url = `${urlApi}${character.replace(':id',id)}`;
        //Defino un objeto que sirve para contener o recibir la informacion 
        //del servidor
        var objRequest = new XMLHttpRequest;
        //Defino el tipo de request como get, la url del servidor y que sera
        //una comunicación asincrona = true
        objRequest.open('GET', url, true)
        //Hacer la petición al servidor, .onload es el callback cuando se hace 
        //la petición request al servidor. Tambien podemos usar .onreadystatechange
        //objRequest.onreadystatechange = function(){
        objRequest.onload = function(){
            if(this.readyState == 4 && this.status == 200){
                let personaje = JSON.parse(this.responseText)
                resolve(personaje)
            }else if(this.readyState == 4 && this.status == 200){
                console.log(id)
                reject(id)
            }            
        }
        objRequest.send()
    })
}

getData(1).then((data)=>{
    console.log(`Hola soy ${data.name}`)
    return getData(2)
}).then((data)=>{
    console.log(`Hola soy ${data.name}`)
    return getData(3)
}).then((data)=>{
    console.log(`Hola soy ${data.name}`)
    return getData(4)
}).then((data)=>{
    console.log(`Hola soy ${data.name}`)
}).catch((id)=>
    console.log(`Ocurrio un error al llamar el id ${id}`)
)

** Cuando al fin entiendes las promesas y el poder de Javascript y sientes que eres tan poderoso que tu cerebro explotara **

Muy buena clase y ahora me queda un poco mejor entendido esto de las promesas porque la verdad si he batallado mucho, espero que con la practica esto sea mucho más facil.

Señor Sacha ¿No los está llevando por camino más difícil?

fetch(url)
  .then(res => res.json())
  .then(json => {
    const characters = json.results;
    characters.map(character => {
      console.log(character.name);
    });
  })
  .catch(err => console.log(err));

.catch para todos que genial 😃

Esto es muy fácil o el profe es muy bueno?

¿Quiere decir que los Callbacks están en desuso?

IDEAS CLAVES

=> Podemos encadenar promesas ejecutando una funcion request con la
primera promesa
* retornando otra funcion con la siguiente promesa que queremos ejecutar
* encadenando con .this
* Y asi sucesivamente
hasta llegar al catch error

=> Las funciones pueden funcionar de manera asincrona y sincrona

Buena clase.

¿Porqué Sacha no usó Fetch API en vez de jQuery para hacer la consulta a la SWAPI?
Comparto el código del este ejercicio con Fetch

function getCharacter (id) {
  return fetch(`https://swapi.co/api/people/${id}/`)
    .then( response => response.json())
    .catch(error => console.error(`Se produjo un error al obtener el personaje ${id}`))
  }
  
  getCharacter(1)
  .then( (character) => {
    console.log(character.name)
    return getCharacter(2)
  })
  .then( (character) => {
    console.log(character.name)
    return getCharacter(3)
  })
  .then( (character) => {
    console.log(character.name)
    return getCharacter(4)
  })
  .then( (character) => {
    console.log(character.name)
    return getCharacter(5)
  })
  .then( (character) => {
    console.log(character.name)
  })
// Acá returno null para que no aparezca otro mensaje de error. Solo mostrará el de Fetch
  .catch(error => null)
const API_URL = 'https://swapi.co/api/'
const PEOPLE_URL = 'people/'

const obtenerPersoaje = (id) => {
  return new Promise((resolve, reject) => {
    const url = `${API_URL}${PEOPLE_URL}${id}`
    $.get(url, {}, (data) => resolve(data))
    .fail(() => reject(id))
  })
}

const mostrarPersonajes = (inicio, fin) => {
  obtenerPersoaje(inicio)
  .then(({ name }) => {
    console.log(`El personaje ${inicio} es ${name}`)
    if (inicio < fin) {
      mostrarPersonajes(inicio+1, fin)
    }
  })
  .catch(id => console.log(`Sucedió un error al obtener el personaje  ${id}`))
}

mostrarPersonajes(1, 30)```

Aquí mi ejemplo con async await + promises alguna sugerencia o mejora?

const API_URL = 'https://swapi.co/api/people/'

async function obtenerPersonaje(id) {
   const url = `${API_URL}${id}`
   const response = await fetch(url)
   const data = await response.json()
   console.log(`Hola, yo soy ${data.name}`)

}
obtenerPersonaje(1)
   .then(()=> obtenerPersonaje(2))
   .then(()=> obtenerPersonaje(3))
   .then(()=> obtenerPersonaje(4))
   .then(()=> obtenerPersonaje(5))
   .then(()=> obtenerPersonaje(6))
   .then(()=> obtenerPersonaje(7))
   .then(()=> obtenerPersonaje(8))
   .then(()=> obtenerPersonaje(9))
   .then(()=> obtenerPersonaje(10))

const obtenerPersonaje = (id) => {
    returnnew Promise((resolve, reject) => {
        const API_URL = 'https://swapi.co/api/';
        const PEOPLE_URL = 'people/';
        const url = `${API_URL}${PEOPLE_URL}${id}`;
        const options = { crossDomain: true };
        $.get(url, options, (response) => resolve(response))
            .catch(() => reject(id))
    })
}

const onResponse = (count, { name }) =>console.log(`${count}. Hola yo soy, ${name}`);
const onError = id => console.log(`Sucedió un error. No se pudo obtener el personaje ${id}`);

const recursive = (count, end) => {
    count++;
    if (count <= end) {
        obtenerPersonaje(count)
            .then((response) => {
                onResponse(count, response)
                recursive(count, end)
            })
            .catch(onError)
    }
}

recursive(0, 8);

¿Hay alguna manera de hacer estos .then con un ciclo? Porque si por ejemplo quisiéramos los primeros 100 personajes creo que sería muy tedioso escribir .then 100 veces

Este artículo me ha ayudado bastante a entenderlo (no mejor, si no) con otros ejemplos:
https://juanmirod.github.io/2016/11/25/promesas-en-javascript.html

Alguien me puede decir si esta es una forma correcta de hacerlo:

Por mucho que intente volver a JS, tiene una sintaxis absurda en comparación con los demás lenguajes xD

Acá un ejemplo donde realizo varias peticiones con un ciclo for, al igual que hago una especie de filtro para que me traiga solo los nombres de aquellos personajes que son hombres.

const API = 'https://swapi.dev/api/'
const PEOPLE_URL = 'people/:id'
const ops = {crossDomain: true}

function obtenerPersonaje(id){
    
    return new Promise((resolve, reject)=> {
        const personurl = `${API}${PEOPLE_URL.replace(':id', id)}`
    
        $.get(personurl, ops, function(people){
            resolve(people)
        })
        .fail(()=> reject(id))
    })
}    

const onError = (id)=>{
    console.log('error al obtener personaje')
}

for (let i = 1; i < 15; i++) {
    const id = i
    obtenerPersonaje(id)
        .then((people)=>{
            //pequeño filtro para obtener solo aquellos personajes que son de sexo masculino
            genero = people.gender
            if(genero === 'male'){
                hombres = [people.name]
                console.log(`Mi nombre es ${hombres}`)
            }
        })
        .catch(onError)
}

En un alarde de genialidad he creado el promisesHELL !!!

const API_URL = `https://swapi.dev/api/`;
const PEOPLE_URL = `people/:id`;
const options = { crossDomain: true};

function obtenerPersonaje(id) {
  return new Promise((resolve, reject) => {
    const url = `${API_URL}${PEOPLE_URL.replace(`:id`, id)}`;
    $
    .get(url, options, function (data) {
      resolve(data);
    })
    .fail(() => reject(id));
  })
}

function onError(id) {
  console.log(`Sucedio un error al obtener el personaje ${id}`);
}

obtenerPersonaje(1)
.then(personaje => {
  console.log(`El personaje 1 es ${personaje.name}`);
  obtenerPersonaje(2)
  .then(personaje2 => {
    console.log(`El personaje 2 es ${personaje2.name}`);
    obtenerPersonaje(3)
    .then(personaje3 => {
      console.log(`El personaje 3 es ${personaje3.name}`);
      obtenerPersonaje(4)
      .then(personaje4 => {
        console.log(`El personaje 4 es ${personaje4.name}`);
        obtenerPersonaje(5)
        .then(personaje5 => {
          console.log(`El personaje 5 es ${personaje5.name}`);
          obtenerPersonaje(6)
          .then(personaje6 => {
            console.log(`El personaje 6 es ${personaje6.name}`);
            obtenerPersonaje(7)
            .then(personaje7 => {
              console.log(`El personaje 7 es ${personaje7.name}`);
            })
            .catch(onError)
          })
          .catch(onError)
        })
        .catch(onError)
      })
      .catch(onError)
    })
    .catch(onError)
  })
  .catch(onError)
})
.catch(onError)

(OJO, ATENCION, CUIDADO, que nadie se equivoque, esto funciona pero no es lo correcto. A mi me sirvió para entender mejor y me pareció divertido compartirlo)

Importante resaltar que el .catch(onError) va a ser de utilidad en caso de fallo de cualquiera de los llamados.

Mi código

const API_URL = 'https://swapi.co/api/'
const PEOPLE_URL = 'people/:id/'

const opts = { crossDomain: true }
var id = 1;


function getPerson(id) {
	return new Promise((resolve, rejected) => {
		const url = `${API_URL}${PEOPLE_URL.replace(':id', id)}`

		$.get(url, opts, function(data) {
			resolve(data)
		})
		.fail(()=> rejected(id))
	})
}


function onError(id) {
	console.error(`sucedio un error al obtener el  personaje ${id}`)
}

function onSucces(persona) {
	console.log(`El personaje ${id} es ${persona.name}`)
	return getPerson(++id)
}

getPerson(id)
	.then(onSucces)
	.then(onSucces)
	.then(onSucces)
	.then(onSucces)
	.then(onSucces)
	.then(onSucces)
	.then(onSucces)
	.catch(onError)

un catch para gobernarlos a todos!

Lo realicé con la API fetch

var misCabeceras = new Headers();
var miInit = { method: 'GET',
  headers: misCabeceras,
   mode: 'cors',
  cache: 'default'
};

function obtenerPersonaje(id) {
 return fetch (`https://swapi.co/api/people/${id}/`, miInit)
 .then (response => response.json())
 .catch (error => console.log(`Error al obtener el personaje ${id}`))
}

obtenerPersonaje(1)
.then ((personaje) =>{
console.log(personaje.name);
return obtenerPersonaje(2)
})
obtenerPersonaje(2)
.then((personaje)=>{
  console.log(personaje.name);
  return obtenerPersonaje(3)
})
obtenerPersonaje(3)
.then((personaje)=>{
  console.log(personaje.name);  
})
.catch(`Error`)

Si quieren testear un caso de error usen el id 17 que da un 404.

**Mi aporte **

// Promesas Encadenadas

/*
A diferencia de los callbacks en el CallbackHell, que terminan estando anidados unos dentro
de otros, cuando se usan Promesas la ejecución de las llamadas no se hacen de manera anidada 
sino de manera encadenada, al mismo nivel una debajo de la otra, lo que hace que el código sea
mucho más legible y mantenible.
*/
// Volviendo al ejemplo anterior

//De esta manera se obtiene datos de la api SWAPI.
const API_URL='https://swapi.co/api/'
const PEOPLE_URL='people/:id'

const opts={ crossDomain: true }


function obtenerPersonaje(id){
// Ya no va a recibir un callback, si no que retornara una promesa.
return new Promise(function(resolve,reject){
    const lukurl=`${API_URL}${PEOPLE_URL.replace(':id', id)}`
    $.get(lukurl, opts,function(data){
        resolve(data)
    })
    .fail(()=>reject(id))
})}
    
function error(id){
    console.log(`sucedio un error con el id ${id}`)
}
// Aca llamamos a la funcion que es una promesa
obtenerPersonaje(1)
.then(function (personaje){
    console.log(`Hola soy ${personaje.name}`)
    // Para obtener la siguiente promesa "seria el anidado de los callbacks"
    return obtenerPersonaje(2)
})
.then(function (personaje2){
    console.log(`Hola soy ${personaje2.name}`)
})
// En el caso de errores
.catch(error)
//Le pasamos el nombre de la funcion que se va a ejecutar.```

Funciona así:
Cuando termine lo resuelto en el .then() de la promesa retornamos obtenerPersonaje(2) con un id (volvemos a llamar a la función y realiza el request), lo pedimos al personaje referente a un id y lo recibimos nuevamente con otro .then 
cuando esa promesa haya sido resuelta. El catch es el mismo para todos

  • Estos requests se están haciendo en serie y no en pararelo

muy util las promesas voy entendiendo un poco mas esta parte que antes parecía bastante abstracta

Ahora si, esto se puso bueno…

const obtenerPersonaje = (id) => {
    return new Promise((resolve, reject) => {
        const API_URL = 'https://swapi.co/api/';
        const PEOPLE_URL = 'people/';
        const url = `${API_URL}${PEOPLE_URL}${id}`;
        const options = { crossDomain: true };
        $.get(url, options, (response) => resolve(response))
            .catch(() => reject(id))
    })
}

const onResponse = (count, { name }) =>console.log(`${count}. Hola Duvan, yo soy: ${name}`);
const onError = id => console.log(`Sucedió un error. No se pudo obtener el personaje ${id}`);

const recursive = (count, end) => {
    count++;
    if (count <= end) {
        obtenerPersonaje(count)
            .then((response) => {
                onResponse(count, response)
                recursive(count, end)
            })
            .catch(onError)
    }
}

recursive(0, 16);```

si usamos un numero random para el parametro “id”, debemos generar este numero cada vez que llamemos a la función, de lo contrario vamos a tener el mismo resultado en cada llamado.

const API_SW_URL = 'https://swapi.co/api/'
const PEOPLE_URL = 'people/:id/'
const OPTS = { crossDomain: true }


function people(id) {
    return new Promise((resolve, reject) => {
        const URL = `${API_SW_URL}${PEOPLE_URL.replace(':id', id)}`

        $
            .get(URL, OPTS, function peopleName({ name }) {
                resolve({ name })
            })
            .fail(() => reject(id))
    })
}

function onError(id) {
    console.log(`no se logro cargar los datos de la nave ${id}`)
}
var limitePersonajes = 15
var randomID = Math.floor(Math.random() * limitePersonajes) + 1

people(randomID)
    .then( ({ name }) => {
        console.log(`Mi personaje favorito es: ${name}`)
        var randomID = Math.floor(Math.random() * limitePersonajes) + 1
        return people(randomID)
    })
    .then( ({ name }) => {
        console.log(`Mi personaje favorito es: ${name}`)
        var randomID = Math.floor(Math.random() * limitePersonajes) + 1
        return people(randomID)
    })
    .then( ({ name }) => {
        console.log(`Mi personaje favorito es: ${name}`)
        var randomID = Math.floor(Math.random() * limitePersonajes) + 1
        return people(randomID)
    })
    .then( ({ name }) => {
        console.log(`Mi personaje favorito es: ${name}`)
        var randomID = Math.floor(Math.random() * limitePersonajes) + 1
        return people(randomID)
    })
    .then( ({ name }) => {
        console.log(`Mi personaje favorito es: ${name}`)
        var randomID = Math.floor(Math.random() * limitePersonajes) + 1
        return people(randomID)
    })
    .then( ({ name }) => {
        console.log(`Mi personaje favorito es: ${name}`)
        var randomID = Math.floor(Math.random() * limitePersonajes) + 1
        return people(randomID)
    })
    .then( ({ name }) => {
        console.log(`Mi personaje favorito es: ${name}`)
        var randomID = Math.floor(Math.random() * limitePersonajes) + 1
        return people(randomID)
    })
    .catch(onError)


EJERCICIO

Un nuevo enemigo a conquistar, las promises 😄

PROMESAS ENCADENADAS
Para encadenar promesas tomamos el código de la clase anterior y le agregaremos algunas cosas en la llamada de la función obtenerUnaPersona.

obtenerUnaPersona(1)
    .then((person)=>{
        console.log(`El personaje 1 es ${person.name}`)
        return obtenerUnaPersona(2)
    })
    .then(person =>{
        console.log(`El personaje 2 es ${person.name}`)
        return obtenerUnaPersona(2)
    })
    .catch(onError)

Aca le estamos diciendo que nos retorne la data de la persona con el id #2 por lo que esta data la redirigimos a un nuevo then donde colocaremos el console log y podemos seguir encadenando otras personas, no es muy difícil de entender la verdad, hasta ahora todo sencillo.
Hagamoslo con uno mas grande;

obtenerUnaPersona(1)
    .then((person)=>{
        console.log(`El personaje 1 es ${person.name}`)
        return obtenerUnaPersona(2)
    })
    .then(person =>{
        console.log(`El personaje 2 es ${person.name}`)
        return obtenerUnaPersona(3)
    })
    .then(person=>{
        console.log(`El personaje 3 es ${person.name}`)
        return obtenerUnaPersona(4)
    })
    .then(person=>{
        console.log(`El personaje 4 es ${person.name}`)
        return obtenerUnaPersona(4)
    })
    .catch(onError)

Hola!!
He estado haciendo variaciones al código para poder llamar a muchas promesas encadenadas sin la necesidad de escribir el código de cada una de ellas. Para eso, me he basado en la recursividad, en la que la función que hace la peticion de un personaje, posteriormente se llamará a sí misma pero haciendo la petición del siguiente personaje. Aquí el código:

function obtenerPersonaje(id) {

    return new Promise((resolve,reject)=>{
        const url = `${API_URL}${PEOPLE_URL.replace(':id',id)}` /*Direccion de donde quiero sacar la info de la API*/
        $
        .get(url, opts, function(data){
            resolve(data) /*Si la llamada a la API fue exitosa, se llamará a .then de la función invocante*/
        })
        .fail(()=>reject(id)) /*Si la llamada a la API fue fallida, se llamará a .catch de la función invocante*/
           
    })
        
}

function onError(id){
    console.log(`Sucedió un error al obtener el personaje ${id}`)
}

var i=0
function funcionObtenerPersonajes(i){
    i+=1
    if(i>10){ //Caso trivial
        console.log("Fin")
    } else {
        obtenerPersonaje(i)
        .then(persona=>{
            console.log(`El personaje ${i} es ${persona.name}`)
            return funcionObtenerPersonajes(i)
        })
        .catch(onError)
    } 
}

funcionObtenerPersonajes(i)

Lo único que hay que tener presente es que dentro de .then, en vez de llamar directamente a la siguiente promesa, lo que hace es volver al tope de la funcion “funcionObtenerPersonajes(i)”, que llamará a la siguiente promesa siempre y cuando se cumpla que i (un contador que va de 1 a 10 porque sólo quiero llamar a 10 personajes) esté dentro del rango que he definido.

No sé cuánto de correcto es lo que he hecho, sólo quería aportar esto porque me parece bastante interesante., ya que en caso de tener que llamar a miles de elementos de una API, tendría que haber una solución para no tener que escribir todo a pelo.

A diferencia de los callbacks en el CallbackHell, que terminan estando anidados unos dentro de otros, cuando se usan Promesas la ejecución de las llamadas no se hacen de manera anidada sino de manera encadenada, al mismo nivel una debajo de la otra, lo que hace que el código sea mucho más legible y mantenible.

La función onError da un undefined asi como esta en la clase

Mi mayor miedo error 503 en https://swapi.co/

while (count < 15) {
  getCharacter(count)
    .then(showInformationCharacter, getCharacter(count+1))
    .catch(showErrorInformation);
  count++;
}```
const API_URL = 'https://pokeapi.co/api/v2/';
const PEOPLE_URL = 'pokemon/:id';

const options = { crossDomain: true }

function obtenerCriatura(id) {
    return new Promise((resolve, reject) => {
        const url = `${API_URL}${PEOPLE_URL.replace(':id', id)}`
        $.get(url, options, function(data) {
        resolve(data);
        })
        .fail(() => reject(id))
    })
}

function onError(id) {
    console.log(`Sucedio un error al obtener el personaje ${id}`);
}

obtenerCriatura(1)
.then((pokemon) => {
    console.log('Pikachu: Pika pikaaa pikaaaachuuuuu');
    console.log(`Pokedex ${pokemon.name} ${pokemon.game_indices[0].game_index}
    es un pokemon de tipo ${pokemon.types[0].type.name}, 
    mide ${pokemon.height*10} centimetros, 
    su habilidad primaria es ${pokemon.abilities[0].ability.name}`)
    return obtenerCriatura(2)
})
.then(pokemon => {
    console.log('Pikachu: Pika pikaaa pikaaaachuuuuu');
    console.log(`Pokedex ${pokemon.name} ${pokemon.game_indices[0].game_index}
    es un pokemon de tipo ${pokemon.types[0].type.name}, 
    mide ${pokemon.height*10} centimetros, 
    su habilidad primaria es ${pokemon.abilities[0].ability.name}`)
    return obtenerCriatura(3)
})
.then(pokemon => {
    console.log('Pikachu: Pika pikaaa pikaaaachuuuuu');
    console.log(`Pokedex ${pokemon.name} ${pokemon.game_indices[0].game_index}
    es un pokemon de tipo ${pokemon.types[0].type.name}, 
    mide ${pokemon.height*10} centimetros, 
    su habilidad primaria es ${pokemon.abilities[0].ability.name}`)
    return obtenerCriatura(4)
})
.then((pokemon) => {
    console.log('Pikachu: Pika pikaaa pikaaaachuuuuu');
    console.log(`Pokedex ${pokemon.name} ${pokemon.game_indices[0].game_index}
    es un pokemon de tipo ${pokemon.types[0].type.name}, 
    mide ${pokemon.height*10} centimetros, 
    su habilidad primaria es ${pokemon.abilities[0].ability.name}`)
    return obtenerCriatura(5)
})
.then(pokemon => {
    console.log('Pikachu: Pika pikaaa pikaaaachuuuuu');
    console.log(`Pokedex ${pokemon.name} ${pokemon.game_indices[0].game_index}
    es un pokemon de tipo ${pokemon.types[0].type.name}, 
    mide ${pokemon.height*10} centimetros, 
    su habilidad primaria es ${pokemon.abilities[0].ability.name}`)
    return obtenerCriatura(6)
})
.then(pokemon => {
    console.log('Pikachu: Pika pikaaa pikaaaachuuuuu');
    console.log(`Pokedex ${pokemon.name} ${pokemon.game_indices[0].game_index}
    es un pokemon de tipo ${pokemon.types[0].type.name}, 
    mide ${pokemon.height*10} centimetros, 
    su habilidad primaria es ${pokemon.abilities[0].ability.name}`)
    return obtenerCriatura(7)
})
.then(pokemon => {
    console.log('Pikachu: Pika pikaaa pikaaaachuuuuu');
    console.log(`Pokedex ${pokemon.name} ${pokemon.game_indices[0].game_index}
    es un pokemon de tipo ${pokemon.types[0].type.name}, 
    mide ${pokemon.height*10} centimetros, 
    su habilidad primaria es ${pokemon.abilities[0].ability.name}`)
})
.catch(onError)

Excelente explicación. Todo muy claro.

Definitivamente se vuelve mucho más legible con el uso de promesas!

suficiente tengo con las promesas de mi ex

Excelente clase!!

function onError (id) {
    console.log(`Sucedió un error al obtener el persona ${id}`);
}

obtenerPersonaje(14)
    .then(personaje => {
        console.log(`El personaje es ${personaje.name}`);
        return obtenerPersonaje(2);
    })
    .then(personaje => {
        console.log(`El personaje es ${personaje.name}`);
        return obtenerPersonaje(3);
    })
    .catch(onError)
const Api = 'https://swapi.dev/api/';
const People = 'people/:id';
const Options = { crossDomain: true };

const obtenerPersonaje = id => {
  return new Promise((resolve, reject) => {

    const Url = `${Api}${People.replace(':id', id)}`;

    $.get(Url, Options, data => resolve(data))
      .fail(() => reject(id))
  })
}
const PeopleRespons = ({ name }) => console.log(`Hola soy, ${name}`)
const ErrorCatch = id => console.log(`Errore en el personaje ${id}`)

obtenerPersonaje(1)
  .then(personaje => {
    PeopleRespons(personaje)
    return obtenerPersonaje(2)
  })
  .then(personaje => {
    PeopleRespons(personaje)

    return obtenerPersonaje(3)
  })
  .then(personaje => {
    PeopleRespons(personaje)

    return obtenerPersonaje(4)
  })
  .then(personaje => {
    PeopleRespons(personaje)

    return obtenerPersonaje(5)
  })
  .catch(ErrorCatch)```
const URL_DE_ACCESO = 'https://swapi.dev/api/'
const PEOPLE_URL = 'people/:id'

const OPTIONS = {crossDomain: true}

function obtenerPersonaje(id){
	return new Promise ((resolve, reject) => {
		const URL_PERSONAJE = `${URL_DE_ACCESO}${PEOPLE_URL.replace(':id', id)}`
		$
		.get(URL_PERSONAJE, OPTIONS, function(data) {
			resolve(data)
		})
		.fail(() =>
			reject (id)
		)
	})
}

function onError(id){
	console.error(`Sucedió un error al obtener el personaje ${id}`)
}

//Resolvemos las promesas encadenadas haciendo un return con el siguiente id y añadiendo los .then que necesitemos

obtenerPersonaje(1)
.then(person => {
	console.log(`Hola, yo soy ${person.name}, mido ${person.height} cm`)
	return obtenerPersonaje(2)
})
.then(person => {
	console.log(`Hola, yo soy ${person.name}, mido ${person.height} cm`)
	return obtenerPersonaje(3)
})
.then(person => {
	console.log(`Hola, yo soy ${person.name}, mido ${person.height} cm`)
	return obtenerPersonaje(4)
})
.then(person => {
	console.log(`Hola, yo soy ${person.name}, mido ${person.height} cm`)
	return obtenerPersonaje(5)
})
.then(person => {
	console.log(`Hola, yo soy ${person.name}, mido ${person.height} cm`)
	return obtenerPersonaje(6)
})
.then(person => {
	console.log(`Hola, yo soy ${person.name}, mido ${person.height} cm`)
	return obtenerPersonaje(7)
})
.then(person => {
	console.log(`Hola, yo soy ${person.name}, mido ${person.height} cm`)
	return obtenerPersonaje(90)
})
.catch(onError)```

/* --------------------PROMISES---------------

  1. Las promises surgieron para solucionar el problema de los callback hell
  2. Una Promesa es un objeto q representa la Finalizacion exitosa o FRACASO de una operacion ASINCRONA
  3. Cuando creamos una promesa figura en Estado Pending - Una vez resuelta su estado sera FulFilled. Ante un Error su estado sera Rejected
  4. Para crear una Promesa utilizamos “new Promise”

Una promesa envia un callback la cual lleva 2 parametros

  1. Resolve
  2. Rejected
    En la funcion callback podremos saber si el proceso se produjo de manera correcta o no.
    Si fue correcto utilizaremos la funcion “resolve()”, enviando de vuelta como parametro el valor que se haya conseguido como resultado.
    Si algo fallo usaremos la funcion “Rejected()”, enviando el motivo de error.
const API_URL = 'https://swapi.dev/api/'

 const PEOPLE_URL = 'people/:id'
 const OPTIONS = { crossDomain: true }

function obtenerPersonaje (id) {

// creacion de la promesa
return new Promise ((resolve, reject) => {

  //creacion de la URl
  const URL = `${API_URL}${PEOPLE_URL.replace(':id', id)}`

  $
  .get(URL, OPTIONS, function(data) {
      resolve(data)
})
    .fail(() => reject(id))

})
}

//Creacion de una funcion de errores
const onError = (id) => console.log(`Ocurrio un error y no se pudo obtener al personaje ${id}`);

//Invocacion de la funcion obtener personajes

obtenerPersonaje(1)
//En caso de exito tratamos con un "then" indicando el resultado de la Promesa
.then(personaje => {
    console.log(`EL personaje 1 es ${personaje.name}`)
    return obtenerPersonaje(2)
})
.then(personaje => {
    console.log(`EL personaje 2 es ${personaje.name}`)
    return obtenerPersonaje(3)
})
.then(personaje => {
    console.log(`EL personaje 3 es ${personaje.name}`)
    return obtenerPersonaje(4)
})
.then(personaje => {
    console.log(`EL personaje 4 es ${personaje.name}`)
    return obtenerPersonaje(5)
}).then(personaje => {
    console.log(`EL personaje 5 es ${personaje.name}`)
    return obtenerPersonaje(6)
})
// en caso de fallo indicamos el error
.catch(onError)```

Es equivalente el for que usé, a lo visto en el video?. Me parece que es mejor asi

const API_URL = 'https://swapi.co/api/'
const PEOPLE_URL = 'people/:id'
const options = {crossDomain: true}
var id=1

function getCharacter(id){
  var url = `${API_URL}${PEOPLE_URL.replace(':id',id)}`
  return new Promise( (resolve, reject) => {
    $.get(url,options, (data) => resolve(data))
     .fail( () => reject(id))
  })
}

function onError(id){
  console.log(`Sucedio un problema con el personaje ${id}`);
}

function info(person){
  console.log(`Soy ${person.name}`)
}

for (var i = 0; i < 20; i++) {
  getCharacter(id)
    .then(info)
    .catch(onError)
  id+=1
}```

Practica:

les comparto mi codigo de como quedaria si llamaramos a todos los personajes del api

   function getPersonaje(i) {
      obtenerPersonaje(i)
      .then((persona) => {
        console.log(`El personaje ${i} es : ${persona.name}`)
      })
      .catch(onError);
    }
    function llamarPeople(num){
      for (let i = 1; i < num; i++) {
        getPersonaje(i)
      }
    }

    llamarPeople(7);```

Siempre que escuchaba “Promesas” sentía que era complejo pero el problema era que nadie lo sabía explicar bien. Gracias Sacha!

Las funciones resolver y rechazar, al ser llamadas, resuelven o rechazan la promesa, respectivamente. generalmente el ejecutor inicia un procesamiento asíncrono, y luego, una vez que es completado, llama a la función resolver para resolver la promesa o la rechaza si ha ocurrido un error.

Promesas encadenadas

Solo código

const API_URL = 'https://swapi.dev/api/'
const PEOPLE_URL = 'people/:id'
const OPTNS = { crossDomain: true }

function getCaracter(id) {
    return new Promise((resolve, reject) => {
        const URL = `${API_URL}${PEOPLE_URL.replace(':id', id)}`
        $
        .get(URL, OPTNS, function (data) {
            resolve(data)
        })
        .fail(() => reject(id))
    })          
}

function onError(id) {
    console.log(`Sucedió un error al obtener el personaje ${id}`)
}

getCaracter(1)
    .then(caracter => {
        console.log(`El personaje 1 es ${caracter.name}`)
        return getCaracter(2)
    })
    .then(caracter => {
        console.log(`El personaje 2 es ${caracter.name}`)
        return getCaracter(3)
    })
    .then(caracter => {
        console.log(`El personaje 3 es ${caracter.name}`)
        return getCaracter(4)
    })
    .then(caracter => {
        console.log(`El personaje 4 es ${caracter.name}`)
        return getCaracter(5)
    })
    .then( (caracter) => {
        console.log(`El personaje 5 es ${caracter.name}`)
        return getCaracter(6)
    })
    .then( (caracter) => {
        console.log(`El personaje 6 es ${caracter.name}`)
        return getCaracter(7)
    })
    .then( (caracter) => {
        console.log(`El personaje 7 es ${caracter.name}`)
    })
    
    .catch(onError)

Amando las promesas, son super claras.
No se reescribe tanto codigo! Mas aun cuando tiene varios procesos se encadenan

cual es la diferencia en serie y en paralelo?

¿es normal que aun me cueste entender todo esto? ¿como hago para entenderlo al 100%?

a nada de rendirme.
soy fiel creyendo de que cualquier cosa se puede explicar de manera sencilla, en términos simples y en poco tiempo, cosa que no he visto que hagan los supuestos “cracks” de programación.

<code> 
const API_URL = 'https://pokeapi.co/api/v2/'
const POKE_ID = 'pokemon/:id'
const opts = {crossdomain : true}

function mostrarPersonaje (id) {
    return new Promise((resolve, reject) => {
        const URL = `${API_URL}${POKE_ID.replace(':id', id)}`
$
        .get(URL, opts, function(data){
            resolve(data)
        })
        .fail(function(){
            reject(id)
        })
    })
}

function onError(id){
    console.log(`Ocurrio un error con el id : ${id}`)
}

mostrarPersonaje(15)
.then(function(poke){
    console.log(`Elegiste el N° ${poke.id} que corresponde al personaje ${poke.name}`)
   return mostrarPersonaje(16)
.then(function(poke){
    console.log(`Elegiste el N° ${poke.id} que corresponde al personaje ${poke.name}`)
    })
})
.catch(onError)

</code>

Por si alguien tuvo problemas hasta aquí con el JQuery:

const API_URL = 'https://swapi.dev/api/', PEOPLE_URL = 'people/:id/';
const url = `${API_URL}${PEOPLE_URL.replace(':id', 1)}`;
const obtenerPersonaje = (urlArgument) => new Promise( (resolve,reject) => {
    const objetoRequest = new XMLHttpRequest; 
    objetoRequest.open('GET', urlArgument, true);
    objetoRequest.onreadystatechange = (() => {
        if(objetoRequest.readyState == 4) {
            (objetoRequest.status == 200) 
                ? resolve(JSON.parse(objetoRequest.responseText))
                : reject(new Error('Hubo un f*ckin error', urlArgument))
        }
    })
    objetoRequest.send();
});
obtenerPersonaje(url)
    .then(data1 => {
        console.log(`Me llamo ${data1.name}`);
        return obtenerPersonaje(url.replace(1, 2))
    })
    .then(data2 => {
        console.log(`Me llamo ${data2.name}`);
        return obtenerPersonaje(url.replace(1, 3))
    })
    .then(data3 => {
        console.log(`Me llamo ${data3.name}`);
        return obtenerPersonaje(url.replace(1, 4))
    })
    .then(data4 => {
        console.log(`Me llamo ${data4.name}`);
        return obtenerPersonaje(url.replace(1, 5))
    })
    .then(data5 => {
        console.log(`Me llamo ${data5.name}`);
        return obtenerPersonaje(url.replace(1, 6))
    })
    .then(data6 => {
        console.log(`Me llamo ${data6.name}`);
    })
    .catch(err => console.error(err))```

Buena buena

mejor hacerlo con un for


function getPeople(id) {
    obtenerPersonaje(id)
    .then(personaje => {
        console.log(`Hola me llamo ${personaje.result.properties.name}`)
    })
    .catch(onerror);
}

for (let index = 1; index <=82; index++) {
    getPeople(index);
}

Para hacer múltiples llamados es mejor utilizar la recursividad:

const API_URL = 'https://swapi.dev/api/'
const PEOPLE_URL = 'people/:id'

const opts = {crossDomain: true}

function obtenerPersona(id) {
	
	return new Promise((resolve, reject) => {
		const url = `${API_URL}${PEOPLE_URL.replace(':id', id)}`
		$.get(url, opts, function(data) {
			resolve(data)
		}).fail(() => reject(id))
	})
}

function onError(id) {
	console.log('Ocurrió un error con el personaje ' + id)
}

var id = 1
function cicloPersonas(){
	obtenerPersona(id)
		.then(persona => {
			console.log(persona.name)
			id++
			if(id <= 7)
				cicloPersonas()
			else
				console.log('Fin de la transferencia de datos')
		})
		.catch(onError)
}

cicloPersonas()

Si alguien cree que el código puede mejorarse, le agradeceré que deje un comentario.

No veo cómo esto es mejor que las callbacks, si tienes que encadenar lo mismo una y otra vez??

Hola, este es mi aporte.


Online

Offline

quiero compartirles que dentro de los parametros pueden asignar una variable. esta variable la pueden utilizar en el console.log para enumerar el orden del personaje

    .then(function (personaje){
    console.log(`El personaje ${id} es ${personaje.name}`)
    return obtenerPersonaje (id=2)
    })
    .then(function (personaje){
        console.log(`El personaje ${id} es ${personaje.name}`)
        })
<code>

la ventaja que veo de las promesas encadenadas es que puedes controlar detalladamente el orden de obtención de datos por parte del servidor. también puedes controlar que datos quieres obtener.

los ciclos if, switch, while y for no podrían controlar específicamente que datos y en que orden deben ser mostrados. solo se ejecutaría el ciclo, y tal vez mostraría datos que no queremos.

Genial!

ejemplo pero con siclo para recorrerlos todos

const API_URL = 'https://swapi.dev/api/'
const PEOPLE_URL = 'people/:id'
const opts = { crossDomain: true }



function obtenerPersonaje(id){
    return new Promise((resolve, reject) => {
        const url = `${API_URL}${PEOPLE_URL.replace(':id',id)}`

        $
        .get(url,opts,function(date){
            resolve(date)
        })
        .fail(() => reject(id))
    })

   
}
function onError (id){
    console.log(`error al obtener ${id}`)
}

function personaje(i) {
obtenerPersonaje(i)
.then((person)=>{
console.log(soy ${person.name})
})
.catch(onError)
}

function getPeople(num) {
for(let i=1; i<=num; i++){
personaje(i)
}
}

getPeople(17)


Este mismo ejercicio se puede resolver utilizando un ciclo, estrellita al que comente el código para ejecutarlo con ciclo.

Vamos por las Promesas Encadenadas.!!
😃

buenas clases

😃

Acà mi codigo de la clase

/*
Autor: Daniel Páez
URL Autor: github.com/heysoypaez
Tema de la clase: Promesas Encadenadas
Descripción: huyendo de los callback hell, descubriendo el paraiso
*/

/*PROTOCOLO DE VERIFICACIÓN DE FUNCIONAMIENTO
==================================*/
//Imprimiendo algo en la consola
console.log("inicializando archivo");


/*DECLARACIÓN DE VARIABLES
==================================*/
var personajesRender = document.getElementById("output");


/* VARIABLES CONSTANTES DE API REQUERIDA
==================================*/
const API_URL = "https://swapi.co/api/";
const PEOPLE_URL = "people/:id";
const LUKE_URL = `${API_URL}${PEOPLE_URL.replace(":id","1")}`
const options = {crossDomain: true};


/*Para realizar un request siempre es necesario saber la url a la cual queremos acceder*/


/*DECLARACIÓN DE FUNCIONES
========================================================*/


//Funcion para obtener Personajes de Star Wars por su Id
function obtenerPersonaje(id) {

	return new Promise( (resolve,reject) => {


		/*Declaración de Variables
		==============================*/
		const url = `${API_URL}${PEOPLE_URL.replace(":id",id)}`


		/*Declaración de Funciones
		=============================*/
		function successRequest(data) {
				resolve(data)
			}


		/*Peticiones a la API
		============================*/

		// $ === jquery, Usamos Jquery.get para requerir datos de la API
		$.get( url, options, successRequest )

		 //Usamos Jquery.fail para hacer algo especifico si el request falla
		 .fail( () => reject(id))
	})

}


//Funcion para  imprimir la info de los Personajes de Star Wars por su Id
function imprimirInfoPersonajes(character) {
		saludo = `Hola, soy ${character.name}`
		
		if (character.name === "Darth Vader") {
			saludo += ` y soy tu padre.`	
		} 
		
		console.log(saludo)
		//Estoy imprimiendo en el document body el mismo saludo que va a la consola
		personajesRender.innerHTML += `<h4>${saludo}</h4>`
}


function alertarError(id) {
	var mensajeError = `(Desarrollador backend) Malas noticias, hubo un error subiendo el personaje ${id}`;

	console.error(mensajeError);
	alert(mensajeError);
}


/*EJECUCIÓN DE FUNCIONES Y PROMESAS
========================================0*/

obtenerPersonaje(1)
	.then( (personaje) => {

		// la data de personaje la recibimos en resolve(data)
		imprimirInfoPersonajes(personaje)
		return obtenerPersonaje(2)
		//encadenado las promesas

	})
	//Este va a ser personaje 2, lo llamamos 4 lineas arriba en el return
	.then( (personaje) => {

		// la data de personaje la recibimos en resolve(data)
		imprimirInfoPersonajes(personaje)
		return obtenerPersonaje(3)
		//encadenado las promesas
		
	})

	.then( (personaje) => {

		imprimirInfoPersonajes(personaje)
		return obtenerPersonaje(4)
		
	})

	.then( (personaje) => {

		imprimirInfoPersonajes(personaje)
		return obtenerPersonaje(5)
	})

	.then( (personaje) => {

		imprimirInfoPersonajes(personaje)
		//Y aqui dejamos de pedir, retornar más personajes
	})

	.catch(alertarError)
	//El mismo catch funciona para todos

	/* Es importante colocar en el parámetro de la funcion donde buscamos que se ejecute de manera sincronica otra funcion que NO se este ejecutando directamente; puede ser la referencia a la función o su declaración*/

Magnífico, se queda el código más limpio!

En el .then si quisiera saber el id del personaje para utilizarlo e imprimirlo ¿Cómo se puede pasar si el método resolve unicamente acepta un parámetro y ese parámetro es lo que devuelve la API?

Lo digo porque yo intenté hacer el console.log de forma dinámica sin tener que escribir el número de personaje pero no puedo.

Gracias

A alguien le pasa que no llama a más de 7 personajes? ya lo intenté y nada !!!

moustro

un solo Catch para todos… oooo si !

Un forma mas corta y sin uso de un bucle para hacer el ejemplo de la clase es utilizando una función recursiva:

const API_URL = 'https://swapi.co/api/';
const PEOPLE_URL = 'people/:id';
const opts = { crossDomain: true }; 
const obtenerPersonaje = function(id){
    return new Promise((resolve, reject) => {
        const url = `${API_URL}${PEOPLE_URL.replace(':id', id)}`;
    
        $.get(url, opts, (data) => {
            resolve(data);
        })
         .fail(() => reject(id));
    });
}

function onError(id) {
    console.log(`Sucedio un error al obtener el personaje ${id}`);
}

function obtenerPersonajeRecusivamente(idInicio, idFinal){
    if(idInicio <= idFinal) {
        obtenerPersonaje(idInicio)
        .then(data =>{
            console.log(`El personaje ${idInicio} es ${data.name}`);
            idInicio++;
            obtenerPersonajeRecusivamente(idInicio, idFinal);
        })
        .catch(onError);
    }    
}

obtenerPersonajeRecusivamente(1, 7);

¿Cómo hacemos para que no termine la ejecución al resultar un error?

Asi puedes crear ciclos de cuantos personajes quieras y de form sincrona. Y solo escribes un ‘.then’

const URL_API = "https://swapi.co/api/";
const PEOPLE_URL = "people/:id";
const opts = { crossDomain: true };

function obtenerPersonaje(id) {
  return new Promise((resolve, reject) => {

    const url = `${URL_API}${PEOPLE_URL.replace(':id', id)}`;
    $
      .get(url, opts, function (data) {
        resolve(data)
      })
      .fail( () => reject(id) )

  }).then(function(personaje) {
    console.log(`El personaje ${id} es ${personaje.name}`);
      if (id < 5) {
        return obtenerPersonaje(id + 1)
        id++
      }
  }).catch(function(id) {
    console.log(`Ha ocurrido un error con el personaje ${id}`);
  })

}

obtenerPersonaje(1)```

Promesas encadenas

const API_URL = 'https://swapi.co/api/'
const PEOPLE_URL = 'people/:id'
const opts = {crossDomain:true}

function obtenerPersonaje(id){
    return new Promise((resolve, reject)=>{
        const url = `${API_URL}${PEOPLE_URL.replace(':id',id)}`
        $
        .get(url, opts, function(data){
            resolve(data)
        })
        .fail(()=> reject(id))
    })
}

function onError(id){
    console.log(`Sucedio un error al obtener el personaje ${id}`)
}
// los request se haces en serie y no paralelo
obtenerPersonaje(1)
    .then( personaje => {
        console.log(`El personaje 1 es ${personaje.name}`)
        return obtenerPersonaje(2)
    })
    .then(personaje =>{
        console.log(`El personaje 2 es ${personaje.name}`)
        return obtenerPersonaje(3)
    })
    .then(personaje =>{
        console.log(`El personaje 3 es ${personaje.name}`)
        return obtenerPersonaje(4)
    })
    .then(personaje =>{
        console.log(`El personaje 4 es ${personaje.name}`)
        return obtenerPersonaje(5)
    })
    .then(personaje =>{
        console.log(`El personaje 5 es ${personaje.name}`)
        return obtenerPersonaje(6)
    })
    .then(personaje =>{
        console.log(`El personaje 6 es ${personaje.name}`)
        return obtenerPersonaje(7)
    })
    .then(personaje =>{
        console.log(`El personaje 7 es ${personaje.name}`)
    })
    .catch(onError)

Yo lo hice de esta manera y me funciono, no se si será profesional jaja

JS↓

const API_URL = 'https://swapi.co/api/'
const PEOPLE_URL = 'people/:id'
const opts = {crossDomain:true}
var id = 1
function obtenerPersonaje(id){

  return new Promise((resolve, reject) => {
    const url = `${API_URL}${PEOPLE_URL.replace(':id', id)}`
  $
    .get(url, opts, function (data){
      resolve(data)
    })
    .fail(() => reject(id))

  })
  .then(personaje => {
    console.log(`El personaje ${id} es ${personaje.name}`)
    if (id<5) return obtenerPersonaje(id+=1)
  })
  .catch(onError)

}

function onError(id){
  console.log(`Sucedió un error al obtener el personaje ${id}`)
}

obtenerPersonaje(id)```

Aparece un error al utilizar el id 2 con swapi


const url_api = 'https://swapi.co/api/'
const url_people = 'people/:id'
const opcion = {crossDomain:true}

function ejecutar(id){
    
    return new Promise((resolve,reject) =>{
     
     const url = `${url_api}${url_people.replace(':id',id)}`   
      
     
      $.get(url,opcion,function (data){
    
          resolve(data)
      })
       
            
    .fail(() => reject(id))        
        
    })
    
}


function onError(id){
    console.log(`sucedio un error al obtener el personaje ${id}`)
}

for (i = 1; i<= 18; i++){

ejecutar(i)
.then(function(personaje){
    console.log(`el personaje es ${personaje.name}`)
})

.catch(onError)

}```
const url_api = 'https://swapi.co/api/'
const url_people = 'people/:id'
const opcion = {crossDomain:true}

function ejecutar(id){
    
    return new Promise((resolve,reject) =>{
     
     const url = `${url_api}${url_people.replace(':id',id)}`   
      
     
      $.get(url,opcion,function (data){
    
          resolve(data)
      })
       
            
    .fail(() => reject(id))        
        
    })
    
}


function onError(id){
    console.log(`sucedio un error al obtener el personaje ${id}`)
}



ejecutar(1)

.then(personaje1 =>{
    
    console.log(`el personaje es ${personaje1.name}`)
    return ejecutar(2)
    
})

.then(personaje2 => {
     
    console.log(`el personaje es ${personaje2.name}`)
    return ejecutar(3)
})

.then(personaje3 =>{
    
    console.log(`el personaje es ${personaje3.name}`)
    return ejecutar(4)
})

.then(personaje4 =>{
    
      console.log(`el personaje es ${personaje4.name}`)
})

.catch(onError)

Encadenando Promesas

Para encadenar una promesa esta se vuelve a llamar a la función en el return, y entonces se encadena otro .then

Por ej:

getCharacter(1)
  .then(character => {
    console.log(`El personaje 1 es ${character.name}`)
    return getCharacter(2)
  })
  .then(character => {
    console.log(`El personaje 2 es ${character.name}`)
  })

Con ello nuestro código se vuelve más legible, en lugar de encadenarlo con llaves, paréntesis, llaves, paréntesis, como se hacía con los callbacks, ahora se encadena uno debajo del otro, haciéndolo mucho más claro.

Además si en alguna promesa sucede algún error, tenemos un solo catch para todas.

const API_URL = "https://swapi.co/api/";
const PEOPLE_URL = "people/:id";
const opts = { crossDomain: true };

function obtener_personaje(id) {
	return new Promise((resolve, reject) => {
		const url = `${API_URL}${PEOPLE_URL.replace(":id", id)}`;
		$.get(url, opts, function(data) {
			resolve(data);
		}).fail(() => reject(id));
	});
}

function on_error(id) {
    console.log(`Sucedio un error al obtener el personaje ${id}`)
}


obtener_personaje(1)
    .then(personaje => {console.log(`El personaje 1 es ${personaje.name}`)
    return obtener_personaje(2)
    })
    .then(personaje => {console.log(`El personaje 2 es ${personaje.name}`)
    return obtener_personaje(3)
    })
    .then(personaje => {console.log(`El personaje 3 es ${personaje.name}`)
    return obtener_personaje(4)
    })
    .then(personaje => {console.log(`El personaje 4 es ${personaje.name}`)
    return obtener_personaje(5)
    })
    .then(personaje => {console.log(`El personaje 5 es ${personaje.name}`)
    return obtener_personaje(6)
    })
    .then(personaje => {console.log(`El personaje 6 es ${personaje.name}`)
    })
    .catch(on_error)```

Las Promises se usan solo para cuando hacemos funciones asíncronas?

Alguien esta utilizando el api de marvel?

Las promesas son mas legibles y fáciles de mantener. Pero representa una ventaja en la eficiencia con respecto a los callbacks?