No tienes acceso a esta clase

隆Contin煤a aprendiendo! 脷nete y comienza a potenciar tu carrera

Generators

19/26
Recursos

Aportes 115

Preguntas 16

Ordenar por:

驴Quieres ver m谩s aportes, preguntas y respuestas de la comunidad?

馃挕 饾棖饾椆饾棶饾榾饾棽 #饾煭饾煵: 饾棜饾棽饾椈饾棽饾椏饾棶饾榿饾椉饾椏饾榾 饾煭饾煵/饾煯饾煭 馃挕
.
Un generador en JavaScript consta de una funci贸n generadora que muestra un objeto iterable Generator. La palabra reservada yield se usa para pausar y reanudar una funci贸n generadora.
Fuente: aqu铆
.

  • La estructura del Generador consta con la palabra function seguido de un aster铆sco * : function* 茅sta es una funci贸n generadora heredada.
  • El resultado que se quiere obtener se coloca al lado derecho de yield, puede ser de cualquier tipo (string, num茅rico, objetos, etc) y se puede tener tantos yield que se desee.
//Declaraci贸n de la funci贸n del Generador
function* gen(){
	yield 1;
	yield 2;
	yield 3;
}

Para poder iterar con el generador, se puede inicializar un valor con la funci贸n generadora:

//Expresi贸n de la funci贸n Generadora
const g = gen();

Entre las propiedades del iterador est谩 next():

//Llamada del m茅todo next en el objeto del Generador
console.log(g.next()); //Imprime el primer yield: {value: 1, done: false} 

next() permite acceder a la funci贸n del generador y obtener con yield dos valores: value y el estado de done, es decir si tenemos yield 1; y mandamos a imprimir el resultado con next() obtenemos `{value: 1, done: false}鈥:

  • El 1 por el valor al lado derecho del primer yield.
  • Y done es false porque mientras haya otro yield por operar ser谩 falso.
  • Ser谩 true cuando se ejecute cuatro veces next() y la salida mostrar谩 {value: undefined, done: true}. 脡sto se debe a que ya no hay mas nada que mostrar, porque se mand贸 a imprimir un cuarto elemento y el generador solo tiene 3 yield.
    .

Para obtener solo el valor de value, se escribe next().value de 茅sta forma:

//Llamada del m茅todo next en el objeto del Generador
console.log(g.next().value); //Imprime el primer yield: 1
console.log(g.next().value); //Imprime el segundo yield: 2
console.log(g.next().value); 
console.log(g.next().value); //Si se coloca un cuarto console, la consola indica "Undefined"

.
鉁忥笍 Ejemplo usando for 鈥 of:

//Declaraci贸n de la funci贸n del Generador pasando un argumento
function* iterate(array){
    for(let value of array){ //El loop del for revisa cada elemento del array
        yield value; //value es asignado en cada ciclo
    }
}

const it = iterate(['Oscar', 'Omar', 'Ana', 'Lucia', 'Juan']); 

//la diferencia con el ejemplo anterior es que el iterador se le pasa un argumento
console.log(it.next().value); //Imprime el primer elemento del array: Oscar
console.log(it.next().value); //Imprime el segundo elemento del array: Omar
console.log(it.next().value);
console.log(it.next().value);
console.log(it.next().value); //Si se coloca un sexto console, la consola indica "Undefined"

Mi solucion al reto:

Ser铆a bueno que en lugar de tirar conceptos solamente, se explique qu茅 uso se le dar铆a en la vida real. No todos los que llegan a este curso tienen la experiencia suficiente, como par abstraer por s铆 mismos, en qu茅 aplicar esta funcionalidad. Queda adem谩s pendiente explicar que esto genera un iterador, sus ventajas, y qu茅 significa el done: false, del objeto que devuelve el iterator.next().

Aqui un video que explica un poco mas a fondo los generators:

https://www.youtube.com/watch?v=6wHGcrVpA2U

Un peque帽o aporte de el reto

import fetch from "node-fetch";
const API = 'https://api.escuelajs.co/api/v1';

/*creamos la funcion de fetchData la cual utiliza la APi y retornamos la informacion en un tipo objeto JSON, implementando la logica de async y await, en este ejemplo
usamos una funcion tradicional*/
 const fetchData = async (urlApi) => {
    const response = await fetch(urlApi);
    const data = await response.json();
    return data;
}

/*creamos la funcion que realiza las solicitudes en este caso usaremos tambien yield y el "*"" al lado de function para identificar un generator
Tambien usamos async y await para hacer el llamado de los productos y demas */
async function* anotherFunction (urlApi) {
    const products = await fetchData(`${urlApi}/products`);
    const product = await fetchData(`${urlApi}/products/${products[0].id}`);
    const category = await fetchData(`${urlApi}/categories/${product.category.id}`);

    //Se utiliza yield para dar una pausa a la ejecucion y utilizamos .next() para dar inicio a el codigo
    yield console.log(products);
    yield console.log(product.title);
    yield console.log(category.name);
}

const g = anotherFunction(API);
g.next().value;
g.next().value;
g.next().value;

Reto resuelto馃挌

import fetch from "node-fetch";
const API = 'https://api.escuelajs.co/api/v1';


function getData(urlAPI){
    return fetch(urlAPI)
}

 
async function anotherFunction(urlAPI){
    const response = await getData(urlAPI)
    const data =  await response.json()
    return data;
}



async function* iterateGet(){
   const products = await anotherFunction(`${API}/products`);
   const product = await anotherFunction(`${API}/products/${products[0]?.id}`);
   const category = await anotherFunction(`${API}/categories/${product?.category?.id}`);

   yield console.log(products);
   yield console.log(product.title);
   yield console.log(category.name);

}

const g = iterateGet()

g.next().value;
g.next().value;
g.next().value;

Reto:

import fetch from "node-fetch";
const API = 'https://api.escuelajs.co/api/v1';

async function fetchData(urlApi){
    const response = await fetch(urlApi);
    const data = await response.json();
    return data;
}

async function* iterData (urlApi){
    try{
        const products = await fetchData(`${urlApi}/products`);
        yield console.log(products[12]);

        const product = await fetchData(`${urlApi}/products/${products[0].id}`);
        yield console.log(products[20]);

        const category = await fetchData(`${urlApi}/categories/${product.category.id}`);
        yield console.log(products[30]);

        
        console.log('Finalizo');

    } catch (error) {
        console.log(error);
    }
}
const res = iterData(API);
res.next();
res.next();
res.next();
res.next();

Aqui les dejo informacion sobre las funciones generadores del MDN:

  • Los generadores son funciones de las que se puede salir y volver a entrar. Su contexto (asociaci贸n de variables) ser谩 conservado entre las reentradas.
  • La llamada a una funci贸n generadora no ejecuta su cuerpo inmediatamente; se devuelve un objeto iterador para la funci贸n en su lugar.
  • Cuando el metodo next() del iterador es llamado , el cuerpo de la funci贸n generadora es ejecutado hasta la primera expresi贸n yield, la cual especifica el valor que ser谩 retornado por el iterador o con, yield*, delega a otra funci贸n generadora.
  • El m茅todo next() retorna un objeto con una propiedad value que contiene el valor bajo el operador yield y una propiedad done que indica, con un booleano, si la funci贸n generadora ha hecho yield al 煤ltimo valor.

Aqu铆 dejo el desarrollo que realic茅 para el desaf铆o 馃槂 ![](

Mi solucion seria la siguiente:

  • En los navegadores modernos, await de nivel superior funciona, siempre que estamos dentro de un m贸dulo.
  • Tam
import fetch from "node-fetch";
const API = 'https://api.escuelajs.co/api/v1';

async function fetchData (urlApi){ 
    const res   = await fetch(urlApi); 
    const data  = await res.json();
    return data; 
}

async function* anotherFn(urlApi){
    try {
        const products  = await fetchData(`${urlApi}/products`);
        yield products[0];

        const product   = await fetchData(`${urlApi}/products/${products[0].id}`);
        yield product.title;

        const category  = await fetchData(`${urlApi}/categories/${product?.category?.id}`);
        yield category.name

    } catch (err) { 
        console.error(err);
    }
}

let promiseGenerator = anotherFn(API)

console.log((await promiseGenerator.next()).value)
console.log((await promiseGenerator.next()).value)
console.log((await promiseGenerator.next()).value)

Otra forma mas soportanda por navegadoes antiguos

import fetch from "node-fetch";
const API = 'https://api.escuelajs.co/api/v1';

async function fetchData (urlApi){ 
    const res   = await fetch(urlApi); 
    const data  = await res.json();
    return data; 
}

async function* anotherFn(urlApi){
    try {
        const products  = await fetchData(`${urlApi}/products`);
        yield products[0];

        const product   = await fetchData(`${urlApi}/products/${products[0].id}`);
        yield product.title;

        const category  = await fetchData(`${urlApi}/categories/${product?.category?.id}`);
        yield category.name

    } catch (err) { 
        console.error(err);
    }
}

async function aux(urlApi){
    let promiseGenerator = anotherFn(urlApi)

    console.log((await promiseGenerator.next()).value)
    console.log((await promiseGenerator.next()).value)
    console.log((await promiseGenerator.next()).value)
    
}

aux(API)

De una forma breve, obtuve la data de categor铆as. Por supuesto se podr铆a agregar nuevas peticiones.


import axios from "axios";

const URL = ' https://api.escuelajs.co/api/v1/categories';

async function* getData() {
    const data = await axios.get(URL);
    yield console.log(data);
}

const g = getData();
console.log(g.next().value)
const BASE_URL = 'https://api.escuelajs.co/api/v1';

const fetchData = async (urlApi) => {
    try {
        const response = await fetch(urlApi);
        return await response.json();
    } catch (error) {
        console.error(error);
    }
};


function* arrayGenerator(array = []) {
    for (const value of array) {
        yield value;
    }
}

function* requester() {
    yield fetchData(`${BASE_URL}/products?offset=0&limit=5`);
    yield fetchData(`${BASE_URL}/products/1`);
    yield fetchData(`${BASE_URL}/categories/2`);
}

// ------------------------------------------------------------


async function main() {
    
    // case 1 - iterate over an array of products
    const products = await fetchData(`${BASE_URL}/products?offset=0&limit=5`);
    const product  = await fetchData(`${BASE_URL}/products/${products[0].id}`);
    const category = await fetchData(`${BASE_URL}/categories/${product.category.id}`);
    
    const productsIterator = arrayGenerator(products);

    console.log(productsIterator.next().value);
    console.log(productsIterator.next().value);
    
    // case 2 - iterate over an array of promises
    const requestsIterator  = arrayGenerator(await Promise.all([
        fetchData(`${BASE_URL}/products/17`),
        fetchData(`${BASE_URL}/products/30`),
        fetchData(`${BASE_URL}/products/51`),
    ]));

    console.log(requestsIterator.next().value);
    console.log(requestsIterator.next().value);
    console.log(requestsIterator.next().value);

    // case 3 - generator of requests
    const requesterIterator = requester();

    console.log(await requesterIterator.next().value);
    console.log(await requesterIterator.next().value);
    console.log(await requesterIterator.next().value);
}

main();

Mi soluci贸n al reto

import fetch from "node-fetch";
const API = 'https://api.escuelajs.co/api/v1';

const fetchData = async (urlApi) => {
  const response = await fetch(urlApi);
  const data = await response.json();
  return data;
}

async function* anotherFunction() {
  const products = await fetchData(`${API}/products`)
  yield products;
  const product = await fetchData(`${API}/products/${products[0].id}`);
  yield product;
  const category = await fetchData(`${API}/categories/${product.category.id}`);
  yield category;
}

const info = anotherFunction();

info.next().then((response) => console.log(response.value)).catch((error) => console.error(error));
info.next().then((response) => console.log(response.value.title)).catch((error) => console.error(error));
info.next().then((response) => console.log(response.value.name)).catch((error) => console.error(error));
function* gen() {
    yield 1;
    yield 2;
    yield 3;
}

const g = gen();
console.log(g.next().value);
console.log(g.next().value);
console.log(g.next().value);
//con la propiedad .netx se van recorriendo los yield por lo que en cada ocasi贸n nos da un valor diferente

function* iterate(array){
    for (let value of array) {
        yield value
    }
}

const it = iterate(['oscar', 'dante', 'ana', 'lucia', 'juan'])
console.log(it.next().value);
console.log(it.next().value);
console.log(it.next().value);
console.log(it.next().value);
console.log(it.next().value);
console.log(it.next().value); //como no hay siguiente valor arroja undefined

Aqu铆 mi soluci贸n al Challenge


Deber铆a ser m谩s claro y mencionar que yield, retorna un objeto con 2 propiedades, value y done, el cu谩l es false si a煤n quedan elementos por iterar o true, si ya completo el ciclo. es por este motivo que usa it.next().value posts acceder a esta propiedad.

Perm铆teme explicarte sobre los generadores en JavaScript y darte un ejemplo pr谩ctico.
.
En JavaScript, un generador es una funci贸n especial que puede pausar su ejecuci贸n y luego reanudarla en un punto espec铆fico. A diferencia de una funci贸n regular, que se ejecuta de principio a fin y devuelve un valor final, un generador puede producir una secuencia de valores a medida que se va ejecutando. Estos valores se generan uno por uno, bajo demanda, lo que hace que los generadores sean 煤tiles para trabajar con colecciones de datos grandes o para generar secuencias infinitas.
.
Los generadores en JavaScript se definen utilizando la sintaxis de funci贸n de generador, que se ve as铆:

function* miGenerador() {
  // C贸digo del generador
  yield valor;
  // M谩s c贸digo del generador
}

La palabra clave function* indica que est谩s creando una funci贸n generadora. Dentro del generador, puedes utilizar la palabra clave yield para pausar la ejecuci贸n y devolver un valor. El generador se reanuda cada vez que se llama a next() en el objeto generado, y la ejecuci贸n contin煤a desde el punto donde se hizo la pausa.
.
Aqu铆 tienes un ejemplo pr谩ctico para comprenderlo mejor. Supongamos que deseas generar una secuencia de n煤meros pares utilizando un generador:

function* generadorNumerosPares() {
  let num = 0;
  while (true) {
    yield num;
    num += 2;
  }
}

const miGenerador = generadorNumerosPares();

console.log(miGenerador.next().value); // Salida: 0
console.log(miGenerador.next().value); // Salida: 2
console.log(miGenerador.next().value); // Salida: 4
console.log(miGenerador.next().value); // Salida: 6

En este ejemplo, creamos un generador llamado generadorNumerosPares(). Utilizamos un bucle while (true) para generar infinitos n煤meros pares. En cada iteraci贸n, pausamos la ejecuci贸n con yield y devolvemos el n煤mero actual. Luego, incrementamos el n煤mero en 2 para la siguiente iteraci贸n.
.
Al llamar a next() en el objeto generado miGenerador, obtenemos el siguiente valor de la secuencia. Cada llamada a next() reanuda la ejecuci贸n del generador desde el punto donde se hizo la pausa, generando as铆 una secuencia infinita de n煤meros pares.
.
Espero que este ejemplo te haya ayudado a comprender mejor los generadores en JavaScript. Si tienes m谩s preguntas, no dudes en hacerlas.

馃摚 Utilizando Generadores en JavaScript

.
En la programaci贸n con JavaScript, los generadores pueden marcar una gran diferencia al manejar operaciones costosas o trabajar con grandes cantidades de datos.
.

  • 馃殌 Producir y procesar 鈥榖ajo demanda鈥: En lugar de generar todos los datos de una vez (lo que puede agotar memoria y recursos), los generadores nos permiten producir y procesar datos 鈥榖ajo demanda鈥. Esto significa que cada dato se genera justo cuando lo necesitamos, optimizando el uso de memoria y distribuyendo la carga de trabajo a lo largo del tiempo.
    .
    Esto es particularmente 煤til para:
    • Manejo de grandes conjuntos de datos
    • Creaci贸n de flujos de datos infinitos
    • Gesti贸n eficiente de paginaci贸n de datos
      .
  • Optimizaci贸n de operaciones as铆ncronas costosas: Imagina que tienes un array de 30 elementos, y cada uno tarda 2 segundos en cargarse. Si utilizas un bucle for o forEach, tendr铆as que esperar un minuto completo para procesar todos los elementos. Pero con un generador, puedes comenzar a trabajar con cada elemento tan pronto como est茅 disponible, es decir, cada 2 segundos, sin tener que esperar a que todos est茅n listos.
    .
    Esto optimiza tu c贸digo y mejora la experiencia del usuario al brindar respuesta inmediata con cada elemento cargado, en lugar de hacerlo esperar hasta que todo est茅 listo. 馃挕
    .
    Recuerda: los generadores son solo una de las herramientas en tu caja de herramientas de JavaScript. 隆脷salos donde sea apropiado para hacer tu c贸digo m谩s eficiente y f谩cil de entender!
    .
![](https://static.platzi.com/media/user_upload/code-98b6a926-d9a0-42d3-9815-0d4a1857e033.jpg)
```js async function fetchData(urlApi) { const response = await fetch(urlApi) const data = await response.json() return data } async function* getData(urlApi) { try { const products = await fetchData(`${urlApi}/products`) const product = await fetchData(`${urlApi}/products/${products[0].id}`) const category = await fetchData(`${urlApi}/categories/${product.category.id}`) yield products[0] yield product.title yield category.name } catch (error) { console.error(error) } finally { console.log('This will always be executed') } } const data = getData(API) data.next().then(({ value }) => console.log(value)) data.next().then(({ value }) => console.log(value)) data.next().then(({ value }) => console.log(value)) ```Esta ser铆a mi soluci贸n

solcion :

import fetch from "node-fetch";
const API = "https://api.escuelajs.co/api/v1";

async function* fetchDataGenerator(urlApi) {
  const response = await fetch(urlApi);
  const data = await response.json();
  yield data;
}

const anotherFunction = async (urlApi) => {
  try {
    const generator = fetchDataGenerator(urlApi);

    const products = (await generator.next()).value;
    const product = (await generator.next()).value;
    const category = (await generator.next()).value;

    console.log(products);
    console.log(product.title);
    console.log(category.name);
  } catch (error) {
    console.error(error);
  }
};

anotherFunction(API);

Un ejemplo para lo que yo veo que serviria esto es para controlar un bucle infinito, ejemplo馃憞

function* contador() {
  let i = 0;
  while (true) {
    yield i;
    i++;
  }
}

const generador = contador();

console.log(generador.next().value); // 0
console.log(generador.next().value); // 1
console.log(generador.next().value); // 2

asi devuelve el valor actual de i de forma controlada.

Les comparto mi resumen de esta clase 馃槃

Yo utilice el generador solo para mostrar los primeros tres productos de la API ```js import fetch from 'node-fetch'; const API = 'https://api.escuelajs.co/api/v1'; async function fetchData (urlApi) { const response = await fetch(urlApi); const data = await response.json(); return data; } async function anotherFunction(urlApi){ //Generator funcionara para mostrar los productos que se requieran function* iterate(array){ for (let value of array){ yield value } } try{ const products = await fetchData(`${urlApi}/products`); const product = await fetchData(`${urlApi}/products/${products[0].id}`); const category = await fetchData(`${urlApi}/categories/${product.category.id}`); //el generator solo muestra los primeros tres elementos del array products const it = iterate(products); console.log(it.next().value); console.log(it.next().value); console.log(it.next().value); console.log(`脠l producto selecionado es: ${product.title}`); console.log(category.name); }catch(error){ console.log(error); } } anotherFunction(API); ``` ![]()
import fetch from "node-fetch";
const API = 'https://api.escuelajs.co/api/v1';

async function fetchData(urlApi) {
  const response = await fetch(urlApi);
  const data = await response.json();
  return data;
}

async function* genData(urlApi) {
  try {
    const products = await fetchData(`${urlApi}/products`);
    yield console.log(products);

    const product = await fetchData(`${urlApi}/products/${products[0].id}`);
    yield console.log(product.title);

    const category = await fetchData(`${urlApi}/categories/${product.category.id}`);
    yield console.log(category.name);
  } catch (error) {
    console.error(error);
  }
}

const data = genData(API);

data.next().value;
data.next().value;
data.next().value;

Objetos Generator

Tradicionalmente, las funciones en JavaScript se ejecutan hasta completarse y la invocaci贸n de una muestra un valor cuando se alcanza la palabra clave聽return. Si se omite la palabra clave聽return, en una funci贸n se mostrar谩 impl铆citamente聽undefined.

En el siguiente c贸digo, por ejemplo, declaramos una funci贸n聽sum()聽que muestra un valor que es la suma de dos argumentos enteros:

// A regular function that sums two values
function sum(a, b) {
  return a + b
}

Al invocar la funci贸n se muestra un valor que es la suma de los argumentos:

const value = sum(5, 6) // 11

Sin embargo, una funci贸n generadora no muestra un valor de inmediato y como alternativa se muestra un objeto聽Generator聽iterable. En el siguiente ejemplo, se declara una funci贸n y se le asigna un valor de devoluci贸n 煤nico, como en una funci贸n est谩ndar:

// Declare a generator function with a single return value
function* generatorFunction() {
  return 'Hello, Generator!'
}

Cuando invoquemos la funci贸n generadora, mostrar谩 el objeto聽[Generator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Generator), que podemos asignar a una variable:

// Assign the Generator object to generator
const generator = generatorFunction()

Si esta fuera una funci贸n regular, esperar铆amos que聽generator聽nos proporcionara la cadena mostrada en la funci贸n. Sin embargo, lo que realmente obtenemos es un objeto en estado聽suspended. Al invocar聽generator, por lo tanto, obtendremos un resultado similar al siguiente:

Output
generatorFunction聽{<suspended>}
  __proto__: Generator
  [[GeneratorLocation]]: VM272:1
  [[GeneratorStatus]]: "suspended"
  [[GeneratorFunction]]: 茠* generatorFunction()
  [[GeneratorReceiver]]: Window
  [[Scopes]]: Scopes[3]

El objeto聽Generator聽mostrado por la funci贸n es un聽iterador. Un聽iterador聽es un objeto que tiene un m茅todo聽next()聽disponible, el cual se utiliza para iterar una secuencia de valores. El m茅todo聽next()聽muestra un objeto con propiedades聽value聽y聽done.聽value聽representa el valor mostrado y聽done聽indica si el iterador recorri贸 o no todos sus valores.

Conociendo esto, invocaremos聽next()聽en nuestro聽generator聽y obtendremos el valor y el estado actual del iterador:

// Call the next method on the Generator object
generator.next()

Esto generar谩 el siguiente resultado:

Output
{value: "Hello, Generator!", done: true}

El valor mostrado despu茅s de invocar聽next()聽es聽Hello, Generator!, y el estado de聽done聽es聽true, ya que este valor provino de un聽return聽que cerr贸 el iterador. Debido a que la operaci贸n del iterador se complet贸, el estado de la funci贸n generadora pasar谩 de聽suspended聽a聽closed. Invocar聽generator聽de nuevo dar谩 el siguiente resultado:

Output
generatorFunction聽{<closed>}

Hasta ahora, solo hemos demostrado que una funci贸n generadora puede ser una alternativa m谩s compleja para obtener el valor聽return聽de una funci贸n. Pero las funciones generadoras tambi茅n tienen caracter铆sticas 煤nicas que las distinguen de las funciones normales. En la siguiente secci贸n, aprender谩 sobre el operador聽yield聽y veremos c贸mo se puede pausar y reanudar la ejecuci贸n de un generador.

Operadores聽yield

Con los generadores se introdujo una nueva palabra clave en JavaScript:聽[yield](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/yield). Con聽yield聽se puede pausar una funci贸n generadora y mostrar el valor que le sigue a聽yield, y as铆 proporcionar una opci贸n ligera para iterar valores.

En este ejemplo, pausaremos la funci贸n generadora tres veces con diferentes valores y mostraremos un valor al final. Luego asignaremos nuestro objeto聽Generator聽a la variable聽generator.

// Create a generator function with multiple yields
function* generatorFunction() {
  yield 'Neo'
  yield 'Morpheus'
  yield 'Trinity'

  return 'The Oracle'
}

const generator = generatorFunction()

Ahora, cuando invoquemos聽next()聽en la funci贸n generadora, se pausar谩 cada vez que encuentre聽yield. Se fijar谩 el valor聽false聽para聽done聽despu茅s de cada聽yield, lo cual indicar谩 que el generador no ha terminado. Una vez que encuentre un聽return, o ya no se encuentren m谩s聽yield聽en la funci贸n,聽done聽pasar谩 a tener el valor聽true聽y el generador habr谩 terminado.

Utilice el m茅todo聽next()聽cuatro veces seguidas:

// Call next four times
generator.next()
generator.next()
generator.next()
generator.next()

Estos dar谩n las siguientes cuatro l铆neas de resultados en orden:

Output
{value: "Neo", done: false}
{value: "Morpheus", done: false}
{value: "Trinity", done: false}
{value: "The Oracle", done: true}

Tenga en cuenta que un generador no requiere un聽return; si se omite, la 煤ltima iteraci贸n mostrar谩聽{value: undefined, done: true}, al igual que cualquier invocaci贸n posterior de聽next()聽despu茅s de que un generador haya finalizado.

En聽ECMAScript 2015, se introdujeron generadores en el lenguaje de JavaScript. Un聽generador聽es un proceso que puede pausarse, reanudarse y producir varios valores. Un generador en JavaScript consta de una聽funci贸n generadora聽que muestra un objeto iterable聽[Generator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Generator).

Los generadores pueden mantener el estado, y proporcionar con ello una forma eficiente de crear iteradores, y encargarse de flujos de datos infinitos que se pueden emplear para implementar desplazamiento infinito en una p谩gina en el frontend de una aplicaci贸n web, para operar con datos de ondas de sonido, y m谩s. Adem谩s, cuando se usan con聽promesas, los generadores pueden imitar la funcionalidad de聽async/await, lo que nos permite abordar el聽c贸digo as铆ncrono聽de una manera m谩s sencilla y legible. Aunque聽async/await聽es una alternativa m谩s frecuente para abordar los casos de uso as铆ncrono m谩s comunes y sencillos, como la obtenci贸n de datos de una API, en los generadores se incluyen funciones m谩s avanzadas que hacen que valga la pena aprender a usarlos.

En este art铆culo, veremos la forma de crear funciones generadoras e iterar objetos聽Generator, la diferencia entre聽yield聽y聽return聽dentro de un generador y otros aspectos vinculados al trabajo con generadores.

Funciones generadoras

Una聽funci贸n generadora聽es una funci贸n que muestra un objeto聽Generator聽y se define con la palabra clave聽function聽seguida de un asterisco (*), como se muestra a continuaci贸n:

// Generator function declaration
function* generatorFunction() {}

De vez en cuando, ver谩 el asterisco junto al nombre de la funci贸n, a diferencia de la palabra clave de la funci贸n; por ejemplo,聽function *generatorFunction(). Esto funciona igual, aunque la de聽function*聽es una sintaxis m谩s aceptada.

Las funciones generadoras tambi茅n pueden definirse en una expresi贸n, como las聽funciones聽regulares:

// Generator function expression
const generatorFunction = function*() {}

Los generadores pueden ser, incluso, los m茅todos de un聽objeto聽o una聽clase:

// Generator as the method of an object
const generatorObj = {
  *generatorMethod() {},
}

// Generator as the method of a class
class GeneratorClass {
  *generatorMethod() {}
}

En los ejemplos de este art铆culo se usar谩 la sintaxis de declaraci贸n de las funciones generadoras.

Nota:聽A diferencia de las funciones regulares, los generadores no se pueden construir a partir de la palabra clave聽new聽ni pueden ser utilizarse junto con las聽funciones de flecha.

Ahora que sabe declarar funciones generadoras, veremos los objetos聽Generator聽iterables que estas muestran.

mi soluci贸n al fetch con async y await usando generators:

async function fetchData(urlApi){
    const response = await fetch(urlApi);
    const data = response.json();
    return data;
}

async function* showFetchData (urlApi) {
    try{
        const products = await fetchData(`${urlApi}/products/`);

        yield console.log(products[55]);
        yield console.log(products[60].title);
    } catch (error) {
        console.log(`el error es ${error}`);
    }
    
}

const showData = showFetchData(API);
showData.next();
showData.next();
![]()**Task:** ![](https://static.platzi.com/media/user_upload/image-e9880a32-36bb-4cf8-9b36-fde8bc1db307.jpg)![](https://static.platzi.com/media/user_upload/image-1bad9db1-02bd-4461-8089-11cbabaabbb5.jpg)![](https://static.platzi.com/media/user_upload/image-a38f07ea-7743-4839-ad98-462475965896.jpg)

19/26 Curso de Asincronismo: Generators

Los generadores en JavaScript son una caracter铆stica que permite crear funciones especiales que pueden pausar su ejecuci贸n y luego reanudarla m谩s tarde. Esto es 煤til para trabajar con secuencias de datos potencialmente largas, como bucles infinitos o grandes conjuntos de datos, sin bloquear la ejecuci贸n del programa. Los generadores se crean utilizando la palabra clave function seguida de un asterisco *, y se utilizan para producir valores de manera incremental a medida que se solicitan.

Aqu铆 tienes un ejemplo simple de c贸mo se define y utiliza un generador en JavaScript:

function* generadorSimple() {
  yield 1;
  yield 2;
  yield 3;
}

// Crear una instancia del generador
const generador = generadorSimple();

// Llamar al generador para obtener valores uno a uno
console.log(generador.next().value); // Imprime 1
console.log(generador.next().value); // Imprime 2
console.log(generador.next().value); // Imprime 3
console.log(generador.next().value); // Imprime undefined (se han agotado todos los valores)


En el ejemplo anterior, la funci贸n generadorSimple es un generador que produce los n煤meros del 1 al 3 utilizando la palabra clave yield. La funci贸n next() se utiliza para obtener el siguiente valor producido por el generador. Cuando el generador se agota, next() devuelve un objeto con la propiedad value igual a undefined.

Los generadores son especialmente 煤tiles en situaciones donde se necesita procesar grandes cantidades de datos de forma eficiente o cuando se deben realizar operaciones de forma as铆ncrona, como en el caso de las promesas y la programaci贸n asincr贸nica.

Puedes usar generadores para crear iteradores personalizados y para simplificar el c贸digo en ciertos casos, especialmente cuando se trabaja con flujos de datos complejos.

Espero sea de utilidad. 馃懆鈥嶐煉

Un objeto Generator resulta de una funci贸n Generator, que se identifica con la palabra reservada function seguida de un asterisco (function*).
.
A una funci贸n generadora se puede salir y volver a entrar, su contexto ser谩 guardado entre las reentradas. La llamada a una funci贸n generadora no ejecuta inmediatamente su cuerpo, en vez de eso devuelve un objeto iterador. El m茅todo 鈥榥ext()鈥 del iterador es llamado, el cuerpo de la funci贸n generadora se ejecuta hasta la primera expresi贸n 鈥榶ield鈥 , la cual tiene el valor que ser谩 retornado.
.
next(), retorna un objeto con la propiedad 鈥榲alue鈥 que contiene el valor bajo el operador 鈥榶ield鈥 y otra propiedad 鈥榙one鈥 que indica con un booleano, si la funci贸n generadora ha hecho yield al 煤ltimo valor.
.
Documentaci贸n馃憤

const API = "https://api.escuelajs.co/api/v1";

async function fetchData(urlApi) {
  const response = await fetch(urlApi);
  const data = await response.json();
  return data;
}

async function* processData(urlApi) {
  try {
    const products = await fetchData(`${urlApi}/products/`);
    for (let product of products) {
      const productData = await fetchData(`${urlApi}/products/${product.id}`);
      yield productData.title;
    }
  } catch (error) {
    yield error;
  }
}

const generator = processData(API);
console.log(await generator.next());
console.log(await generator.next());
console.log(await generator.next());
console.log(await generator.next());
generator.next().then((response) => console.log(response.value));
generator.next().then((response) => console.log(response.value));
generator.next().then((response) => console.log(response.value));
generator.next().then((response) => console.log(response.value));

Seria genial ver una implementaci贸n en casos reales, para entender mejor el porque existe los gen茅ralos鈥

Mi soluci贸n al reto.

import fetch from 'node-fetch'
const API = 'https://api.escuelajs.co/api/v1';

async function fetchData (urlApi) {
    const response = await fetch(urlApi);
    const data = await response.json();
    return data;
} 

async function* iterData () {
    try {
        yield console.log('Loading data...');

        const data = await fetchData(`${API}/products`);
        yield setTimeout(() => {
            console.log(` `);
            console.log(`La informaci贸n referente al producto #1 es:`);
            console.log(`El producto con id ${data[2].id} es ${data[2].title} y tiene un costo de $${data[2].price} COP, y pertenece a la categor铆a ${data[2].category.name}`);
            console.log(` `);
        }, 2000);

        yield setTimeout(() => {
            console.log(`La informaci贸n referente al producto #2 es:`);
            console.log(`El producto con id ${data[4].id} es ${data[4].title} y tiene un costo de $${data[4].price} COP, y pertenece a la categor铆a ${data[4].category.name}`);
            console.log(` `);
        }, 4000);

        yield setTimeout(() => {
            console.log(`La informaci贸n referente al producto #3 es:`);
            console.log(`El producto con id ${data[10].id} es ${data[10].title} y tiene un costo de $${data[10].price} COP, y pertenece a la categor铆a ${data[10].category.name}`);
            console.log(` `);
        }, 6000);
    }
    catch (error) {
        console.log(error);
    }
}

const iter = iterData();

iter.next().value;
iter.next().value;
iter.next().value;
iter.next().value;



import fetch from 'node-fetch';

const API =  'https://api.escuelajs.co/api/v1'; 


async function fetchData(urlApi) {
    const response = await fetch(urlApi);
    const data = await response.json();
    return data;
}
async function* generator(urlApi)  {
    try {
        const products = await fetchData(`${urlApi}/products`);
        yield console.log(products)

        const product = await fetchData(`${urlApi}/product/${products[0].id}`);
        yield console.log(product.tittle);

        const category = await fetchData(`${urlApi}/categories/${product.category.id}`);
        yield console.log(category.name);

    } catch {
        console.error(error);
    }
}
const g = generator(API);
g.next();
g.next();
 

Habr谩 casos de uso reales para eso? :0

19/26 Generators
Imagina que est谩s leyendo un libro muy largo y quieres tomar peque帽os descansos despu茅s de cada cap铆tulo para hacer otras cosas. En lugar de tener que leer todo el libro de una vez, te gustr铆a tener la capacidad de pausar tu lectura despu茅s de cada cap铆tulo y luego continuar desde donde lo dejaste.

Los generadores son como esos puntos de pausa en tu lectura. Son funciones especiales que te permiten generar una serie de valores secuenciales de manera controlada, permitiendo detener y reanudar la ejecuci贸n seg煤n sea necesario.

function* miGenerador() {
  yield 'Hola';   // Genera y devuelve el valor 'Hola'
  yield 'Mundo';  // Genera y devuelve el valor 'Mundo'
  yield '!';      // Genera y devuelve el valor '!'
}

// Creamos una instancia del generador
const generador = miGenerador();

// Iteramos sobre los valores generados usando un bucle o llamando al m茅todo next()
console.log(generador.next().value);  // Imprime 'Hola'
console.log(generador.next().value);  // Imprime 'Mundo'
console.log(generador.next().value);  // Imprime '!'

Tenemos una funci贸n llamada miGenerador que utiliza la sintaxis especial function para indicar que es un generador. Dentro de la funci贸n, usamos la palabra clave yield para generar y devolver valores secuenciales.

Al crear una instancia del generador con const generador = miGenerador(); podemos iterar sobre los valores generados llamando al m茅todo next() del generador. Cada vez que llamamos a next(); el generador se ejecuta hasta alcanzar la siguiente declaraci贸n yield donde se detiene y devuelve el valor generado.

Les comparto como realic茅 el reto. Obtengo un producto diferente en cada llamado del getData al utilizar un generator para pasarle un n煤mero (id) distinto:

import fetch from "node-fetch";
const API = "https://api.escuelajs.co/api/v1";

function* generator(){
    let i = 1;
    while(true){
        yield i;
        i++;
    }
}

const getData = async (urlApi) => {
    const response = await fetch(urlApi);
    return response.json();
}

const displayData = async () => {
    try{
        const product = await getData(`${API}/products/${gen.next().value}`);
        console.log(product);
    } catch(error){
        console.error(error);
    }
}

const gen = generator();
displayData()
displayData()
displayData()
displayData()
displayData()

Resumen:

/*-----------------------Generadores-----------------------*/

//Son funciones especiales que pueden pausar su ejecuci贸n, luego volver al punto donde se quedaron, recordando su scope y seguir retornando valores.

function* iterate(array)  { //colocar * al lado de function define un generador
    for (let value of array) {
        yield value; //yield solo funciona en generadores. Pausa la funci贸n y devuelve el valor que se tiene hasta ese momento. Puede haber m谩s de 1.
    }
}

const it = iterate(["Oscar", "Alexa", "David", "Gerlis"]);

console.log(it.next().value); //Oscar //next() es un m茅todo que devuelve un objeto cuyas propiedades son value (para el valor de yield) y done (valor true si ya se termin贸 la ejecuci贸n total de la funci贸n o false si a煤n falta)
console.log(it.next().value); //Alexa //por cada invocaci贸n la funci贸n se reanuda desde el 煤ltimo yield
console.log(it.next().value); //David
console.log(it.next().value); //Ulises
console.log(it.next().value); //undefined //si ya no hay nada que recorrer, es decir, ya se ejecut贸 totalmente la funci贸n

Para m谩s detalle este tema se hablo en el curso de ECMASCRIPT HISTORIA Y VERSIONES, espec铆ficamente en esta clase: https://platzi.com/clases/3504-ecmascript-6/51765-generator/

Esta es mi implementaci贸n para el reto:


Ac谩 pueden probar el c贸digo:

import fetch from 'node-fetch';
const API = 'https://api.escuelajs.co/api/v1';

async function fetchData(urlApi){
  const response = await fetch(urlApi);
  const data = await response.json();
  return data;
}


async function* iterData(urlApi) {
  try {
    const products = await fetchData(`${urlApi}/products`);
    yield console.log(products[3]);

    const product = await fetchData(`${urlApi}/products/${products[3].id}`)
    yield console.log(product.title);

    const category = await fetchData(`${urlApi}/categories/${product.category.id}`)
    yield console.log(category.name);
    
  } catch (error) {
    console.error('Error', error);
  };
};

const iteracion = iterData(API);
iteracion.next();
iteracion.next();
iteracion.next();

Esta es mi solucion del challenge

async function* getData(urlApi) {
    const response = await fetch(urlApi);
    const data = await response.json();
    yield await data
}


var response = await getData(`${API}/products`).next();
const products = response.value;
response = await getData(`${API}/products/${products[0].id}`).next();
const product = response.value;
response = await getData(`${API}/categories/${product.category.id}`).next();
const category = response.value;

console.log(product);
console.log(product.title);
console.log(category.name);![]

EXTRA!!! aqui dejo el ejemplo para la llamada recurrente del GET product si tuvieramos una lista de products id y quisieramos traer espec铆ficamente esos productos

const productsA = [7,8,9,10,11,12];

async function* getProductData(productID) {
    const response = await fetch(`${API}/products/${productID}`);
    const data = await response.json();
    yield await data
}

for (let product of productsA) {
    const productData = await getProductData(product).next();
    console.log(productData.value)
}

Mi soluci贸n al reto:

Este es mi aporte, es algo directo al utilizar 鈥済enerator鈥 dentro del cuerpo de anotherFunction del ejercicio anterior de async/await. Imprimo los primeros 3 productos de la lista pero de seguir escribiendo it.next().value sigue iterando la lista de productos enviada por FakeApi

import fetch from 'node-fetch';
const API = 'https://api.escuelajs.co/api/v1';

const fetchData = async (urlApi) => {
    const response = await fetch(urlApi);
    const data = await response.json();
    return data;
}

const anotherFunction = async (urlApi) => {
    try{
        const products = await fetchData(`${urlApi}/products`);

        const it = iterator(products)
        
        console.log(it.next().value)
        console.log(it.next().value)
        console.log(it.next().value)
    }catch(err){
        console.error(err);
    }
}

function* iterator(array){
    for(let product of array){
        yield product
    }
}

anotherFunction(API)

Mi soluci贸n al reto:

import fetch from "node-fetch";
const API = 'https://api.escuelajs.co/api/v1';

async function fetchData(urlApi) {
    const response = await fetch(urlApi);
    const data =  await response.json();
    return data;
  }

async function* anotherFunction(urlApi) {
      const products = await fetchData(`${urlApi}/products`);

      for (let i = 0; i < products.length; i++) {
        const product = await fetchData(`${urlApi}/products/${products[i].id}`);
        const category = await fetchData(`${urlApi}/categories/${product.category.id}`);

        yield console.log(`T铆tulo del producto: ${product.title} 
        Categor铆a: ${category.name}`);
  
  }
}

const dt = anotherFunction(API);


dt.next();
dt.next();
dt.next();
dt.next();
dt.next();

/*
T铆tulo del producto: nuevo titulo 
        Categor铆a: Shoes
T铆tulo del producto: Handmade Cotton Fish 
        Categor铆a: Shoes
T铆tulo del producto: Awesome Concrete Shirt 
        Categor铆a: Others
T铆tulo del producto: Handmade Metal Towels 
        Categor铆a: Clothes
T铆tulo del producto: Handmade Metal Bacon 
        Categor铆a: Electronics
T铆tulo del producto: Handmade Soft Fish 
        Categor铆a: Electronics
T铆tulo del producto: Recycled Plastic Pants 
        Categor铆a: Shoes
...
*/

Les dejo un aporte
El codigo esta pensado para obtener todas las categorias que tenemos disponibles de los productos del api de Platzi, despues haciendo uso de un generador vamos mostrando una a una de las categorias.
Espero les ayude en algo o que puedan mejorarlo

import fetch from "node-fetch";
const API = 'https://api.escuelajs.co/api/v1';

const useFetch = async( urlApi ) => {
    try {
        const categories = [];
        const response = await fetch( `${API}/products` );
        const data = await response.json();
        data.forEach( ( { category } ) => {
            if( !categories.includes( category.name ) ){
                categories.push( category.name );
            }
        });
        return categories;
    } catch ( error) {
        console.log;
    }
};
async function* iterResponse( urlApi ){
    const categories = await useFetch( urlApi );
    for( let category of categories ){
        category;
        yield console.log(category);
    }
    return categories;
}
const data = iterResponse(API); 
data.next();
data.next();
data.next();
data.next();
data.next();

**Generator **
Los generadores son funciones especiales que pueden pausar su ejecuci贸n, luego volver al punto donde se quedaron, recordando su scope y seguir retornando valores.

Estos se utilizan para guardar la totalidad de datos infinitos, a trav茅s de una funci贸n matem谩tica a valores futuros. De esta manera ocupan poca memoria, con respecto a si creamos un array u objeto.

C贸mo utilizar generadores
La sintaxis de los generadores comprende lo siguiente:

  • La palabra reservada function* (con el asterisco al final).

  • La palabra reservada yield que hace referencia al valor retornado cada vez que se invoque, recordando el valor anterior.

  • Crear una variable a partir de la funci贸n generadora.

El m茅todo next devuelve un objeto que contiene una propiedad value con cada valor de yield; y otra propiedad done con el valor true o false si el generador ha terminado.
Si el generador se lo invoca y ha retornado todos sus valores de yield, entonces devolver谩 el objeto con las propiedades value con undefined y un done con true.

// Declaraci贸n
function* nombre(par谩metros){
    yield (primer valor retornado)
    yield (segundo valor retornado)
    ...
    yield (煤ltimo valor retornado)

}

//Crear el generador
const generador = nombre(argumentos)

// Invocacioens
generador.next().value //primer valor retornado
generador.next().value //segundo valor retornado
...
generador.next().value //煤ltimo valor retornado

Ejemplo de un generador
Por ejemplo, creemos un generador para retornar tres valores.

function* generator(){
    yield 1
    yield 2
    yield 3
}

const generador = generator()

generador.next().value //1
generador.next().value //2
generador.next().value //3
generador.next() // {value: undefined, done: true}

Mi soluci贸n al reto:

const API = "https://api.escuelajs.co/api/v1";

async function fetchData(url){
    const response = await fetch(url);
    const data = response.json();
    return data;
}

async function* getData(url){
    try{
        const products = await fetchData(`${url}/products`);
        const product = await fetchData(`${url}/products/${products[0].id}`);
        const category = await fetchData(`${url}/categories/${product.category.id}`);
        
        yield console.log(products);
        yield console.log(product);
        yield console.log(category.name);
    
    }
    catch{
        throw new Error("API Not Found")
    }
    
}
const resultado = getData(API);
resultado.next()
resultado.next()
resultado.next()

En este ejemplo, el profe copia y pega varias veces la misma linea de codigo.
Para poder hacer eso un poquito mas facil y rapido en VS Code, podemos dar click a la linea que queremos repetir, luego presionar Shift + Alt + Flecha abajo el numero de veces que queramos pegar la linea.

Comparto mi soluci贸n al reto.
Toma tu tiempo para resolver y luego puedes ver esta soluci贸n.
*
*
*
*
*
*
*
*
*
*
*

import fetch from 'node-fetch';

const API = 'https://api.escuelajs.co/api/v1';

async function fetchData(urlApi) {
    const response = await fetch(urlApi);
    const data = await response.json();
    return data;
}

async function* iterableFetchData(urlApi) {
    try {
        const products = await fetchData(`${urlApi}/products`);
        yield products;
        const product = await fetchData(`${urlApi}/products/${products[0].id}`);
        yield product;
        const category = await fetchData(
            `${urlApi}/categories/${product.category.id}`
        );
        yield category.name;
    } catch (error) {
        console.log(error);
    }
}

const itFetch = iterableFetchData(API);
const response = async () => {
    const res = await itFetch.next()
    return res.value;
};

console.log(await response());
console.log(await response());
console.log(await response());

Espero que quien a煤n no haya entendido este tema, logre hacerlo con mis notas, intent茅 hacerlo lo m谩s detallado posible.
Son una caracter铆stica de JS que permite escribir funciones que puedan pausarse en diferentes puntos durante la ejecuci贸n, permitiendo una forma m谩s flexible de controlar el flujo de ejecuci贸n. Se define con la palabra reservada function* y dentro de la funci贸n se pueden utilizar yield para devolver un valor y pausar la ejecuci贸n.

Cuando se llama a un generator, se devuelve un objeto de tipo generator, que se puede utilizar para controlar la ejecuci贸n de la funci贸n. Los m茅todos next() y return() se pueden utilizar para avanzar en la ejecuci贸n del generator, y yield para pausar la ejecuci贸n devolviendo un valor.

Son especialmente 煤tiles para trabajar con estructuras de datos grandes o iterables que pueden no estar completamente definidas al momento de la ejecuci贸n. Al utilizar un generator, se pueden obtener los valores de forma incremental, lo que puede ser m谩s eficiente y menos costoso en t茅rminos de memoria.

import fetch from "node-fetch";//permite realizar llamadas http en entornos nodejs

const API = 'https://api.escuelajs.co/api/v1';//creamos una constante con la api a usar

const fetchData = async (urlApi) => {//creamos una funcion asincrona que recipe una variable por parametro
  const response = await fetch(urlApi)//creamos una constante haciendo llamado a una api con el metodo fetch, el await hace referencia a la espera de una promesa
  const data = await response.json()//creamos una constante apartir de response la variable anterior, pero convirtiendo los datos en json, tambien a la espera como promesa
  return data//retornamos los datos convertidos
}

const anotherFunction = async (urlApi) => {//creamos una funcion asincrona que recipe una variable por parametro
  try {//Inicializamos un bloque try para empezar a lanzar peticiones asincronas de datos
    const products = await fetchData(`${urlApi}/products`);//Declaramos la espera de la promesa a obtener los datos de los productos
    function* iterate(array) {//declaramos una funcion generator que reciba un array por parametro
      for (let value of array) {//iteramos los valores del array
      yield value//utilizamos su metodo yield para por cada iteracion devolver y parar en cada dato
      }
    }

    const it = iterate([...products])//declaramos una constante con los datos iterados copiando con un spread operator los datos traidos de la api
    let nextItem = it.next()//delcaramos una variable igualada a it con el metodo next para avanzar en cada dato iterado
    let count = 0//declaramos una variable en 0 para controlar los datos a mostrar

    while (!nextItem.done && count < 2){//declaramos un bucle while, que cuando nextItem.done sea falso y el conteo sea menor a 2
      console.log(nextItem.value)//nos muestre el dato
      nextItem = it.next()//volvemos a declarar nextItem con next() para que avance en la iteracion
      count++//se incrementar cada vez que el metodo next() se activa
    }
    it.return()//termina la iteracion del generator
  }
  catch(err){//Inizializamod el bloque catch por si debe capturar alguna excepcion dada por el bloque try y asi manejar esa excepcion
    console.log(err)
  }
}

anotherFunction(API)

Este es un ejemplo que utiliza una funcion generadora generator function para iterar sobre un array de datos que se obtienen a trav茅s de una API.
Explicaci贸n del generator dentro del try:

  • Se inicia un bloque try para manejar cualquier excepcion que pueda ocurrir durante la ejecuci贸n del codigo.

    try {
    
  • Se llama a la funci贸n as铆ncrona fetchData para obtener los datos de los productos de una API a trav茅s de una URL que se llama a trav茅s del par谩metro urlApi. La variable products almacena el resultado de la promesa resuelta que devuelve fetchData.

    const products = await fetchData(`${urlApi}/products`);
    
  • Se define una funcion generadora llamada iterate que acepta un array como argumento. En este, se utiliza la sintaxis function* para definirla. Dentro de esta funcion, se define un bucle for鈥f que itera sobre cada valor del array y utiliza el operator yield para devolver y detener la ejecuci贸n de la funcion en cada valor.

    function* iterate(array) {
      for (let value of array) {
      yield value
      }
    }
    
  • Se declara una constante it que almacena la iteraci贸n del array products que se realiza con la funcion iterate que se defini贸 anteriormente. Se utiliza el operador de propagaci贸n para copiar los elementos de products en un nuevo array antes de pasarlo como argumento a la funcion iterate.

    const it = iterate([...products])
    
  • Se inicializa una variable nextItem con el resultado de llamar al m茅todo next()
    en el objeto generador it. Esto devuelve un objeto con dos propiedades: value
    (el siguiente valor de la iteraci贸n) y done (un booleano que indica si la iteraci贸n ha terminado). Tambi茅n se inicializa una variable count en 0

    let nextItem = it.next()
    let count = 0
    
  • Se utiliza un bucle while para iterar sobre los valores de la funci贸n generadora, iterate hasta que done sea verdadero o count llegue a 2. En cada iteraci贸n, se muestra el valor actual en la consola y se llama al m茅todo next() en el objeto generador para avanzar a la siguiente iteraci贸n. La variable count se incrementa en cada iteraci贸n para controlar el n煤mero de valores que se muestran.

    while (!nextItem.done && count < 2){
      console.log(nextItem.value)
      nextItem = it.next()
      count++
    }
    
    
  • Se llama al m茅todo return() en el objeto generador it para finalizar la iteraci贸n del generador. Este m茅todo se utiliza para indicar que la iteraci贸n ha terminado y realizar cualquier limpieza necesaria.

    it.return()
    
    

Esta es la clase que m谩s me vol贸 la cabeza, por ser un incre铆ble dato 馃く

Recurso util para resolver el reto

Existe algo llamado 鈥済eneradores asincronos鈥 los cuales son permiten crear funciones generadoras que soporten la sintaxis async await, esto es especialmente util para poder manejar promesas y sus resultados con los generadores:

async function* createAsyncGenerator() {
  yield await Promise.resolve(1);
  yield await Promise.resolve(2);
  yield await Promise.resolve(3);
}
const asyncGen = createAsyncGenerator();
asyncGen.next()
  .then((res) => console.log(res.value)); // 1
asyncGen.next()
  .then((res) => console.log(res.value)); // 2
asyncGen.next()
  .then((res) => console.log(res.value)); // 3

Puedes ver mas aqui: link

Tambien existe otro recurso llamado for await que nos permite iterar un iterador asincrono (en el caso anterior, nos permitiria recorrer el resultado de las 3 promesas como si de un array se tratara):

async function* createAsyncGenerator() {
    yield await Promise.resolve(1);
    yield await Promise.resolve(2);
    yield await Promise.resolve(3);
  }

  async function showPromises(){
    for await(let value of createAsyncGenerator()){
        console.log(value);
    }
  }
  showPromises();

El codigo anterior hace exactament lo mismo que el primero, resuelve las promesas y muestra su valor.

Puedes ver mas aqui: link

Sabiendo esto, resolver el challenge del profesor es un tanto mas sencillo:

import fetch from "node-fetch";
const API = 'https://api.escuelajs.co/api/v1';

async function fetchData(urlAPi){
    const response = await fetch(urlAPi);
    const data = await response.json();
    return data;
}

async function* getData(urlAPi) {
    try {
        const products = await fetchData(`${urlAPi}/products`);
        yield products[0];
        const product = await fetchData(`${urlAPi}/products/${products[0].id}`);
        yield product.title;
        const category = await fetchData(`${urlAPi}/categories/${product.category.id}`);
        yield category.name
        
    } catch (error) {
        console.log(error);
    }
    
}
const showData = async (API) =>{
    for await (let value of getData(API)){
        console.log(value)
    };
}
showData(API)

Esta es la forma en la que yo implemente los generadores, getData obtiene los productos cuando lo necesite y showData los muestra, pero no es la unica posible, existen muchas otras ingeniosas formas en la que los podrias implementar, a ti, 驴Se te ocurre alguna?, dejamela en los comentarios.

Reto

import fetch from "node-fetch";
const API = 'https://api.escuelajs.co/api/v1';

async function fetchData (urlApi) {
    const response = await fetch(urlApi);
    const data = await response.json();
    return data;
}

async function* iterate(urlApi) {
    try {
        const products = await fetchData(`${urlApi}/products`);
        const product = await fetchData(`${urlApi}/products/${products[0].id}`);
        const category = await fetchData(`${urlApi}/categories/${product.category.id}`);

        yield console.log(products);
        yield console.log(product.title);
        yield console.log(category.name);

    } catch (error) {
        console.error(error);
    }
}
const it = iterate(API);
it.next();
it.next();
it.next();

Dejo mi soluci贸n para el reto

import fetch from 'node-fetch';
const API = 'https://api.escuelajs.co/api/v1';

async function* fetchData(urlApi) {
    const response = await fetch(urlApi);
    const data = await response.json();
    yield data;
}

async function anotherFn(urlApi) {
    try {
        const products = await (await fetchData(`${urlApi}/products`).next()).value;
        const product = await (await fetchData(`${urlApi}/products/${products[0].id}`).next()).value;
        const category = await (await fetchData(`${urlApi}/categories/${product.category.id}`).next()).value;
        
        console.log('--------PRODUCTS');
        console.log(products);
        console.log('--------PRODUCT');
        console.log(product.title);
        console.log('--------CATEGORY');
        console.log(category.name);
    } catch (error) {
        console.error('Error: ', error);
    }
}

anotherFn(API);

Los 鈥淕enerators鈥 son una funci贸n especial en JavaScript que puede retener su estado y continuar donde lo dej贸 la pr贸xima vez que se llame. Cada vez que se llama a un generador, se ejecuta hasta encontrar la palabra clave** 鈥測ield鈥** y luego detiene su ejecuci贸n hasta que se lo llame de nuevo. Esto significa que puede controlar el flujo de ejecuci贸n de su c贸digo y hacer cosas como crear secuencias infinitas o iterar sobre colecciones.

Un ejemplo de uso:

function* contador() {
  let contador = 0;
  while (true) {
    contador++;
    yield contador;
  }
}

const generador = contador();
console.log(generador.next().value); // 1
console.log(generador.next().value); // 2
console.log(generador.next().value); // 3

DigitalOcean tambien tiene una buena explicaci贸n en espa帽ol sobre los "Generators"
https://www.digitalocean.com/community/tutorials/understanding-generators-in-javascript-es

Mi solucion al reto. Lo hice sin especificar los numeros de id de cada producto.
1
2
3
4
5
6
7
8
9
10

import fetch from "node-fetch";
const API = 'https://api.escuelajs.co/api/v1';

//function that converts in a objeto the info that we got from a url
async function fetchData(urlApi){   
    const response =await fetch(urlApi);
    const data = await response.json();
    return data;
}

function* i (array){
    for (let value of array){
        yield value
    }
}
//fills consts with the objects that we get from the url, the url is feeded for the last response
const anotherFunction = async (urlApi) =>{ 
    try{
        const products = await fetchData(`${urlApi}/products`);
        
        const propertyValues = Object.values(products); //convert the object into a iterable array     
        
        const it = i(propertyValues);
        console.log(it.next().value);
        console.log(it.next().value);
        console.log(it.next().value);
        console.log(it.next().value);
    }
    catch(error){console.log(error); }
}
anotherFunction(API);

Este generator lo utilizaria para hacer, por ejemplo un onboarding, cuando realizas un onboarding tienes darle siguiente varias veces en una interfaz grafica. Podr铆a utiliarlo para ello.

Apunte en Notion

Les comparto mi solucion al reto:

import fetch from "node-fetch";
const API = 'https://api.escuelajs.co/api/v1';

const fetchData = async (urlApi) => {
    const response = await fetch(urlApi);
    const data = await response.json();
    return data;
}

async function* anotherFn(urlApi) {
    try {
        const products = await fetchData(`${urlApi}/products`);
        const product = await fetchData(`${urlApi}/products/${products[15]?.id}`);
        const category = await fetchData(`${urlApi}/categories/${product?.category?.id}`);

        yield console.log(products);
        yield console.log(product?.title);
        yield console.log(category?.name);

    } catch (error) {
        console.error(error);

    } finally {
        console.log('Finally');
    }
}

const gen = anotherFn(API);
console.log(gen.next());
console.log(gen.next());
console.log(gen.next());
console.log(gen.next());
console.log(gen.next());

Solution:

Les dejo por aqu铆 un recurso que me sirvi贸 bastantito para entender m谩s a fondo los posibles usos de los generators y su estructura 馃槂

Mi soluci贸n:

no es la mejor, pero es lo que se me ocurri贸.

Saludos, mi solucion

import fetch from 鈥渘ode-fetch鈥;
const API = 鈥https://api.escuelajs.co/api/v1鈥;

const fetchData = async (urlApi) => {
const response = await fetch(urlApi);
const data = await response.json(); //estructura de los datos transformandolos en json
return Object.entries(data); //Convirtiendo el JSON a ARRAY y retornandolo
};
function* iterate(array) {
for (let value of array) {
yield value; //value es asignado en cada ciclo
}
}
const Show = async (urlApi, numItems) => {
try {
const result = await fetchData(${urlApi}/products);
const it = iterate(result);
for (let i = 0; i < numItems; i++) {
console.log(it.next().value);
}
} catch (error) {
console.error(error);
}
};

Show(API, 5); // mostrar 5 productos

Soluci贸n al reto usando for await :

El c贸digo:

import fetch from "node-fetch";
const API = "https://api.escuelajs.co/api/v1";

async function fetchData(urlApi) {
	const rawData = await fetch(`${urlApi}`);
	const data = await rawData.json();
	return data;
}

const counter = async function* (urlApi) {
	const products = await fetchData(`${urlApi}/products`);
	yield products[1];

	const product = await fetchData(`${urlApi}/products/${products[140].id}`);
	yield product.title;

	const category = await fetchData(`${urlApi}/categories/${product.category.id}`);
	yield category;
};

const counterGenerator = counter(API);

for await (const promise of counterGenerator) {
	console.log(promise);
}

Mi reto 鈿★笍

import fetch from "node-fetch";
const API = "https://api.escuelajs.co/api/v1";

async function fetchData(urlApi) {
  const response = await fetch(urlApi);
  const data = response.json();
  return data;
}

async function* generator(urlApi) {
    try {
        const products = await fetchData(`${urlApi}/products`)
        const product = await fetchData(`${urlApi}/products/${products[219].id}`)
        const category = await fetchData(`${urlApi}/categories/${product.category.id}`)

        yield console.log(products[219])
        yield console.log(product.title)
        yield console.log(category.name)

    } catch (error) {
        throw new Error('Data not found')
    } finally {
        console.log('Finally')
    }
}


const gen = generator(API)
gen.next()
gen.next()
gen.next()
gen.next()

Aqu铆 he escrito un c贸digo m谩s dinamico sobre como podemos hacer uso de los generators.

function* iterate(array) {
  for (let value of array) {
    yield value;
  }
}

const array = [1, 2, 3, 4, 5];
const it = iterate(array);

array.forEach(() => {
  console.log(it.next().value);
})

Lo que hacemos arriba es definir la funci贸n iterate y que reciba un array. El array que recibimos lo iteramos con un bucle for鈥f y hacemos yield del valor.

Definimos el array a usar y luego la variable que contiene la funci贸n iterate. Como queremos iterar todos los elementos del array, podemos usar un forEach en el array y as铆 ejecutar el it por cada elemento dentro del array y por lo tanto obtendremos todos los valores del array sin necesidad de hacerlo a mano.

Mi soluci贸n con resolviendo el challenge con generators

import fetch from 'node-fetch';
const API = 'https://api.escuelajs.co/api/v1';

const fetchData = async (urlApi) => {
	const response = await fetch(urlApi);
	const data = await response.json();
	return data;
};

async function* iterData(urlApi, data) {
	for (let element of data) {
		const product = await fetchData(`${urlApi}/products/${element.id}`);
		const category = await fetchData(
			`${urlApi}/categories/${product.category.id}`
		);
		yield { product: product.title, category: category.name };
	}
}

const iter = await fetchData(`${API}/products`).then((products) =>
	iterData(API, products)
);

iter.next().then(({ value, done }) => console.log(value));
iter.next().then(({ value, done }) => console.log(value));

Mi soluci贸n del reto:

import fetch from 'node-fetch';
const API = 'https://api.escuelajs.co/api/v1';

async function fetchData(urlApi) {
  const response = await fetch(urlApi);
  const data = await response.json();
  return data;
}


async function* anotherFunction(urlApi) {
  try {
    const products = await fetchData(`${urlApi}/products`);
    yield products;

    const product = await fetchData(`${urlApi}/products/${products[0].id}`);
    yield product;

    const category = await fetchData(`${urlApi}/categories/${product.category.id}`);
    yield category;

  } catch(error) {
    console.log(error);
  }
};

const data = anotherFunction(API);

data.next().then((result) => {
  console.log(result.value);
});
data.next().then((result) => {
  console.log(result.value.title);
});
data.next().then((result) => {
  console.log(result.value.name);
});

Una funcion generadora, nos permite tener secuencias de resultados; es decir no un unico resultado. Analogamente una funcion generadora es como si estuviesemos viendo una serie en Netflix, realizamos un pedido de una hamburguesa, en el momento mas interesante de la serie, llega el delivery a nuestra casa y toca el timbre. Ponemos en Pausa la serie, recibimos el pedido y regresamos a ver la serie. Esto seria una funcion generadora. Puede ser detenida en medio de la ejecucion, y luego puede ser ejecutada nuevamente.

As铆 me va quedando el c贸digo para el challenge del fetch con generadores:

import fetch from "node-fetch";
const API = "https://api.escuelajs.co/api/v1";

async function fetchData(urlApi) {
    const response = await fetch(urlApi);
    const data = await response.json();
    return data;
}

async function* anotherFn(urlApi) {
    try {
        const products = await fetchData(`${urlApi}/products`);
        const product = await fetchData(`${urlApi}/products/${products[0].id}`);
        const category = await fetchData(`${urlApi}/categories/${product.category.id}`);
        yield console.log(products);
        yield console.log(product.title);
        yield console.log(category.name);
    } catch (error) {
        console.log(error);
    }
}

const it = anotherFn(API);
it.next();
it.next();
it.next();

Mi soluci贸n al reto:

import fetch from 'node-fetch';

const API = 'https://api.escuelajs.co/api/v1';

const fetchData = async (urlApi) => {
  const response = await fetch(urlApi)
  const data = await response.json()
  return data;
}

async function* iterableData(url) {

  const products = await fetchData(`${url}/products`)
  yield products;

  const product = await fetchData(`${url}/products/${products[0].id}`)
  yield product.title;

  const category = await fetchData(`${url}/categories/${product.category.id}`)
  yield category.name;
}

const data = iterableData(API)

const it1 = await data.next()
const value1 = await it1.value
console.log(value1)

const it2 = await data.next()
const value2 = await it2.value
console.log(value2)

const it3 = await data.next()
const value3 = await it3.value
console.log(value3)

Tomas Garcia (@tomasotano25)

para hacer el reto, copie la l贸gica de algunas clases pasadas. solo le inclu铆 yield y le cambie la manera de imprimirlo con next(). siento que no hice gran cosa pero me costo un poco

import fetch from "node-fetch";
const API = 'https://api.escuelajs.co/api/v1'


async function fetchData(urlApi) {
    const response =  await fetch(urlApi);
    const data =  await response.json();
    return data;
}

 async function* fetchApi (urlApi)  {
    try{
        const products = await fetchData(`${urlApi}/products`)
         const product = await fetchData(`${urlApi}/products/${products[0].id}`)
         const category = await fetchData(`${urlApi}/categories/${product.category.id}`)
  
         yield console.log(products);
         yield console.log(category.name);
         yield console.log(product.title);

         
    }catch (error){
        console.error(error);
    }
}

const log = fetchApi(API)
    console.log(log.next());
    console.log(log.next());
    console.log(log.next());



Hola, dejo mi solucion con la que considero que es la mejor forma de implementar un generator con async await para este escenario (para requerir uno a uno los productos):


import fetch from "node-fetch";
const API = "https://api.escuelajs.co/api/v1";

//Getting information by fetch, transform it to a JSON file
async function fetchData(urlAPI) {
   const response = await fetch(urlAPI);
   return response.json();
}

//Best way to use generator in this exercice is for getting the products one by one
async function* getProductsOneByOne(urlAPI) {
   try {
      const products = await fetchData(`${urlAPI}/products`);
      for (let value of products) yield value;
   } catch (error) {
      yield console.error(error);
   }
}

//Show 2 product in a list with ID and Title
const products = getProductsOneByOne(API);
console.log("List of products:");
console.log(
   `${(await products.next()).value.id} : ${
      (await products.next()).value.title
   }`
);
console.log(
   `${(await products.next()).value.id} : ${
      (await products.next()).value.title
   }`
);

Mi humilde aportaci贸n y soluci贸n al reto:

import fetch from "node-fetch";
const API = 'https://api.escuelajs.co/api/v1';

async function fetchData(urlApi) {
    const response = await fetch(urlApi);
    const data = await response.json();
    return data;
}

const anotherFn = async (urlApi) => {
    try {
        const products = await fetchData(`${urlApi}/products`);
        const product = await fetchData(`${urlApi}/products/${products[0].id}`);
        const category = await fetchData(`${urlApi}/categories/${product.category.id}`);

        function* iterate(urlApi) {
            yield console.log(products);
            yield console.log(product.title);
            yield console.log(category.name);
        }

        const iterateFetchData = iterate(API);
        iterateFetchData.next();
        iterateFetchData.next();
        iterateFetchData.next();

    } catch (error) {
        console.error(error);
    }
}

anotherFn(API);

Agradecer铆a sus comentarios y/o aportaciones sobre errores y mejoras en mi c贸digo para seguir aprendiendo.

Un saludo.

hey coders!!

Aqu铆 mi soluci贸n al ejercicio! no la dejo visible porque yo se que tu puedes lograrlo!
*
*
*
*
*
*
*
*
*
*

import fetch from 'node-fetch';
const API = 'https://api.escuelajs.co/api/v1';

//L贸gica de async: ir por los datos, luego esperar por ellos y finalmente retornarlos hacia el usuario
async function fetchData(urlApi) { //siempre async antes de function
    const response = await fetch(urlApi); //hacemos uso del fetch() y await 
    const data = await response.json(); //estructura de los datos transformandolos en json
    return data; //retorna la informaci贸n de la API que estamos solicitando
}

//tambi茅n se puede colocar la palabra async antes del argumento y se usa arrow function
const anotherFunction = async (urlApi) => {
    //En try estar谩 todo lo que queremos que suceda con la l贸gica de la aplicaci贸n
    try{
        const products = await fetchData(`${urlApi}/products`);
        function* iterate(array){
            for(let value of array){
                yield value;
            }
        }
        const it =iterate(products);
        console.log(it.next().value)
        console.log(it.next().value)
        console.log(it.next().value)
        console.log(it.next().value)
        
    } catch(error) { //Atraparemos un error en caso de que haya uno
        console.error(error);
    }
}

anotherFunction(API);

aunque no entiendo mucho logre esto hacerlo gracias al aporte de mis compa帽eros ! 馃槃

import fetch from 'node-fetch';
const API = 'https://api.escuelajs.co/api/v1';

async function fetchData (urlApi){
    const response = await fetch(urlApi);
    const data = await response.json();
    return data;
}
async function* iterate2 (urlApi){
    try{
        const products= await fetchData(`${urlApi}/products`);
        const product = await fetchData(`${urlApi}/products/${products[0].id}`);
        const category = await fetchData(`${urlApi}/categories/${product.category.id}`);
        console.log(products);
        console.log(product.title);
        console.log(category.name);
    }
    catch(error){
        console.error(error);
    }
    yield console.log(products);
    yield console.log(product.title);
    yield console.log(category.name);
}
iterate2(API);

const p=iterate2(API);
p.next().value;
p.next().value;
p.next().value;

Mi soluci贸n para el reto, incluye comentarios, espero se entienda jajaja

import fetch from 'node-fetch';
const API = "https://api.escuelajs.co/api/v1";

async function fetchData(urlAPI) {
    const response = await fetch(urlAPI);
    return response.json();
}

/* Funcion generadora asincrona que hace varias peticiones a la API
   despues de cada peticion, regresamos info con yield

   IMPORTANTE, recordemos que en cada yield, la funcion regresa algo,
   y como estamos con una FUNCION ASINCRONA, REGRESA PROMESAS
*/
async function* anotherFunction(urlAPI) {
    try {
        const products = await fetchData(`${urlAPI}/products`);
        yield products[0];

        const product = await fetchData(`${urlAPI}/products/${products[0].id}`)
        yield product.title;

        const category = await fetchData(`${urlAPI}/categories/${product.category.id}`);
        yield category.name;
    } catch (error) {
        console.error(error);
    }
}

/*
Como REGRESA PROMESAS, tenemos que usar .then()
con destructuracion de bojetos podemos extraer el valor
value, que es lo que en realidad necesitamos
*/
const data = anotherFunction(API);
data.next()
    .then(({ value }) => {
        console.log(value);
    })
data.next()
    .then(({ value }) => {
        console.log(value);
    })
data.next()
    .then(({ value }) => {
        console.log(value);
    })

Recomiendo ver esta conferencia de Anjana Vakil acerca de funciones generadoras, esta muy buena y explica bastantes cosas
馃憠 YouTube

mi soluci贸n espero les ayude mi alternativa

import fetch from "node-fetch";
const urlapi = 'https://rickandmortyapi.com/api/character/';

async function* data(url) {
    yield await fetch(url).then(response => response.json());
};

async function* consulta(url){
    try {
        const totalDimensiones = await data(url).next();
        yield console.log(totalDimensiones.value.info.count);
        const nombre = await data(url+totalDimensiones.value.results[0].id).next();
        yield console.log(nombre.value.name);
        const dimension = await data(nombre.value.origin.url).next();
        yield console.log(dimension.value.dimension);
    } catch (error) {
        console.error(error);
    }
};

const solicitud = consulta(urlapi);
solicitud.next().value;
solicitud.next().value;
solicitud.next().value;

aqu铆 mi aporte

const api = 'https://rickandmortyapi.com/api/character/';

async function* fetchData(url) {
    yield await fetch(url).then(response => response.json());
};

const peticion = async(url) => {
    try {
        const totalDimensiones = await fetchData(url).next();
        console.log(totalDimensiones.value.info.count);
        const nombre = await fetchData(url+totalDimensiones.value.results[0].id).next();
        console.log(nombre.value.name);
        const dimension = await fetchData(nombre.value.origin.url).next();
        console.log(dimension.value.dimension);
    } catch (error) {
        console.error(error);
    }
};

peticion(api);

aqu铆 mi soluci贸n al reto

async function* fetch_Data(url) {
    yield await fetch(url).then(response => response.json());
}

const request = async(url) => {
    try {
        const products = await fetch_Data(`${url}/products`).next();
        console.log(products.value[0]);
        console.log(products.value[0].title);
        console.log(products.value[0].category.name);
    } catch (error) {
        console.error(error);
    }
}

request(API);

yo lo hice usando recursividad para ir haciendo el siguiente llamado 鈥渘ext()鈥

import fetch from 'node-fetch'

async function fetchData(urlApi) {
  const response = await fetch(urlApi)
  const data = await response.json()
  return data
}

async function* iterator () {

  const API = 'https://api.escuelajs.co/api/v1'

  try {
    const products = await fetchData(`${API}/products`)
    yield products

    const product = await fetchData(`${API}/products/${products[156].id}`)
    yield product.title

    const category = await fetchData(`${API}/categories/${product.category.id}`)
    yield category.name

  } catch (e) {
    console.log(e)
  }
}



function runCall (res, iterator) {

  res.then(response => {
    
    if(!response.done) {

      console.log(response)

      res = iterator.next()

      runCall(res, iterator)
    }
  })
}

const it  = iterator()
let response = it.next()

runCall(response, it)

Siguiendo la documentacion de AsyncGenerator en MDN

import fetch from "node-fetch";
const API = 'https://api.escuelajs.co/api/v1';

async function fetchData(urlAPI) {
    // console.log(`async fetchData(${urlAPI}) start`);
    const response = await fetch(urlAPI);
    // console.log(`async fetchData(${urlAPI}) end`);
    return response.json();
}

async function* apiCalls(urlAPI) {
    console.log('async anotherFunction() start');
    try {
        const products = await fetchData(`${urlAPI}/products`);
        yield products;

        const firstProductInResp = products[0];
        const product = await fetchData(`${urlAPI}/products/${firstProductInResp.id}`);
        yield product;

        const category = await fetchData(`${urlAPI}/categories/${product.category.id}`);
        yield category;

    } catch(error) {
        console.error(error);
    } finally {
        console.log('async anotherFunction() end');
    }
}

async function generate() {
    const g = apiCalls(API);

    const products = await g.next();
    console.log(` -> ${products.value.length} products retrieved!!`);
    console.log(' -> first product:\n', products.value[0]);

    const firstProduct = await g.next();
    console.log(` -> first product title: ${firstProduct.value.title}`);

    const category = await g.next();
    console.log(` -> first product - category name: ${category.value.name}`);
}

generate();
 

Mi aporte del challlenge con Generator:

import fetch from 'node-fetch';
const API = 'https://api.escuelajs.co/api/v1';

async function fetchData(urlApi) {
    const response = await fetch(urlApi);       // Recordemos que por debajo fetch usa el concepto de las promesas
    const data = await response.json();
    return data;
}

// Ahora usemos try and catch para manejar errores en las funciones asincronas.
async function* anotherFunction(urlApi) {
    try {
        const products = await fetchData(`${urlApi}/products/`);
        yield console.log(products);

        const product = await fetchData(`${urlApi}/products/${products[0].id}`);
        yield console.log(product.title);

        const category = await fetchData(`${urlApi}/categories/${product.category.id}`);
        yield console.log(category.name);

        // console.log(products);
        // console.log(product.title);
        // console.log(category.name);

    } catch (error) {
        console.log(error);
    }
}

// Llamamos al generador
const af = anotherFunction(API);
af.next();
af.next();
af.next();

Aqu铆 mi challenge antes y despues de leer los comentarios.

Antes:

Despues:

Mi soluci贸n Al reto. Retroalimentaci贸n PLS!
Use un for del tama帽o de la cantidad de elementos que contiene products, para hacer varios pedidos a la API, con informaci贸n individual de cada pedido.
Hasta que punto es buena o mala practica hacerlo asi?

//Aqui llamado como hemos visto hasta ahora para
//correr desde node
import fetch from "node-fetch";
const API = "https://api.escuelajs.co/api/v1";

//construccion de funcion asincrona para consumo de api
async function fetchData(urlApi) {
  const response = await fetch(urlApi);
  const data = await response.json();
  return data;
}
//otra funcion asincrona para consuma de los datos
//de la api
//  !! AQUI IMPLEMENTO LOS GENERADORES
//Lo que hice fue poner en un bucle del tama帽o de la
//cantidad de productos, para poder llamar la data de
//los diferentes productos y mostrarlos en orden
async function* anotherFn(urlApi) {
  try {
    const products = await fetchData(`${API}/products`);
    let product;
    let category;

    //-----
    for (let i = 0; i < products.length; i++) {
      product = await fetchData(`${API}/products/${products[i].id}`);
      category = await fetchData(`${API}/categories/${product.category.id}`);
      yield console.log(
        "Nombre: " + product.title + ", ",
        "Categoria: " + category.name
      );
      //---
    }
  } catch {
    console.error(error);
  }
}
const anoth = anotherFn(API);
// Entonces llamo la data del siguiente y siguiente 
//siempre que quiera
console.log("Aqui empieza");
anoth.next().value;
anoth.next().value;
anoth.next().value;
anoth.next().value;
anoth.next().value;
console.log("Aqui termina");

// RESPONDE

// Aqui empieza
// Aqui termina
// Nombre: Producto actualizadow new,  Categoria: Clothes
// Nombre: Awesome Frozen Bike,  Categoria: Clothes
// Nombre: Handcrafted Granite Bacon,  Categoria: Others
// Nombre: Gorgeous Soft Tuna,  Categoria: Furniture
// Nombre: Tasty Granite Shirt,  Categoria: Shoes


鈿掞笍 RETO: SOLUCI脫N

  • 馃檴 Con Promesas
import fetch from 'node-fetch';
const API = 'https://api.escuelajs.co/api/v1';

async function* fetchData(urlApi) {
    const response = await fetch(urlApi);
    yield await response.json();
}

fetchData(`${API}/products`).next()
    .then(({ value: products, done }) => {
        console.log(products);
        return fetchData(`${API}/products/${products[0].id}`).next();
    })
    .then(({ value: product, done }) => {
        console.log(product.title);
        return fetchData(`${API}/categories/${product.category.id}`).next();
    })
    .then(({ value: category, done }) => {
        console.log(category.name);
    })
    .catch((error) => console.error(error));
  • 鉂わ笍 Con Async-Await
import fetch from 'node-fetch';
const API = 'https://api.escuelajs.co/api/v1';

async function* fetchData(urlApi) {
    const response = await fetch(urlApi);
    yield await response.json();
}

const asyncfunction = async (urlApi) => {
    try {
        const { value: products, done: productsDone } = await fetchData(`${urlApi}/products`).next();
        const { value: product, done: productDone } = await fetchData(`${urlApi}/products/${products[0].id}`).next();
        const { value: category, done: categoryDone } = await fetchData(`${urlApi}/categories/${product.category.id}`).next();

        console.log(products);
        console.log(product.title);
        console.log(category.name);
    } catch (error) {
        console.error(error);
    }
}

asyncfunction(API);

**Mi soluci贸n al reto **

import fetch from 'node-fetch';
const API = 'https://api.escuelajs.co/api/v1';

async function* fetchData(urlApi){
    const response = await fetch(urlApi);
    const data = await response.json();
    yield data;
}

await fetchData(`${API}/products`).next().then((data) => {
    console.log(data.value);
})
.catch((error) => {
    console.log(error);
}).finally(() => {
    console.log('Finally');
});

Mi soluci贸n del reto con Axios.

import axios from "axios";

const API = 'https://api.escuelajs.co/api/v1'


async function* gen(url) {
  const products = await axios(`${url}/products`)
  
  const product = await axios(`${url}/products/${products.data[0].id}`)
  
  const category = await axios(`${url}/categories/${product.data.category.id}`)
  
  yield console.log(products.data[5])
  yield console.log(product.data.title)
  yield console.log(category.data.name)
}

const g = gen(API)
g.next()
g.next()
g.next()

Revisando un poco, voe que para tomar el value utilizando una funcion generadora podemos hacer esto.

/**
 * Se realiza la peticion a la api solicitada
 *
 * @param      {string}  url     Ruta correspondiente a la API.
 * @return     {object}
 */
const requestData = async (url) => {
    const REQUEST = await fetch(url);
    const DATA = await REQUEST.json();
    return DATA;
};

/**
 * Genera las peticiones a la API
 *
 * @param      {string}   url   Ruta del API
 * @return     {Promise}
 */
async function* generateRequest(url) {
    const ITEMS = await requestData(url);
    let count = 0;
    for (let item of ITEMS) {
        yield item;
    }
}

const API = "https://orca-api-pokemon.herokuapp.com";
const GET_DATA = await generateRequest(`${API}/type/fire`);
let breakRequest = false;

do {
    let {value , done} = await GET_DATA.next();
    console.log(value);
    breakRequest = done;
} while(breakRequest !== true);

Para este caso es necesario correr el codigo en la consola del navegador ya que dentro de las nuevas especificaciones de JS podemos utilizar await fuera de una funci贸n que tenga async.

Mi soluci贸n al reto propuesto

const fetch = require("node-fetch");

/**
 * Se realiza la peticion a la api solicitada
 *
 * @param      {string}  url     Ruta correspondiente a la API.
 * @return     {object}
 */
const requestData = async (url) => {
    const REQUEST = await fetch(url);
    const DATA = await REQUEST.json();
    return DATA;
};

/**
 * Genera las peticiones a la API
 *
 * @param      {string}   url   Ruta del API
 * @return     {Promise}
 */
async function* generateRequest(url) {
    const ITEMS = await requestData(url);
    let count = 0;
    for (let item of ITEMS) {
        yield console.log(`Item [${count++}] : %o`, item);
    }
}


const API = "https://orca-api-pokemon.herokuapp.com";
const GET_DATA = generateRequest(`${API}/type/fire`);
GET_DATA.next();
GET_DATA.next();
GET_DATA.next();

un ejemplo de generadores

function* createID(){
    var id = 0;
    while(true)
        yield id++;
}

let gen = createID();

for (let i = 0; i < 20; i++){
    console.log(gen.next().value);
}

A mi se me han ocurrido estas dos formas de resolver el ejercicio:

  1. Versi贸n 1:

  2. Versi贸n 2:

    En mi opini贸n esta segundo forma queda mucho m谩s legible y comprensible.
    Diganme que les parece, si encuentran alg煤n fallo o alguna mejora!! Saludos 馃挌

Mi soluci贸n al reto:

import fetch from "node-fetch";
const API = 'https://api.escuelajs.co/api/v1'

async function fetchData(url){
  const response = fetch(url)
  const data = (await response).json()
  return data
}

async function* inter(url) {
  const products = await fetchData(`${url}/products`)
  yield console.log(products[0])

  const product = await fetchData(`${url}/products/${products[0].id}`)
  yield console.log(product.title)

  const category = await fetchData(`${url}/categories/${product.category.id}`)
  yield console.log(category.name)
}

const int = inter(API)
int.next()
int.next()
int.next()

Mi aporte a este reto:

//importamos el fectch y creamos la constante con nuestra API de platzi
import fetch from "node-fetch";
const API = "https://api.escuelajs.co/api/v1";
//creamos la funcion para consumir la api y transformarlo a json
const fecthData = async (urlApi) => {
  const response = await fetch(urlApi);
  const datajson = response.json();
  return datajson;
};
//hacemos las peticiones usando el async await y la funcion generadora
const anotherFunction = async function* pepe(urlApi) {
  const r1 = await fecthData(`${API}/products`);
  const r2 = await fecthData(`${API}/products/${r1[5].id}`);
  const r3 = await fecthData(`${API}/categories/${r2.category.id}`);
  //controlamos la salida de nuestra funcion con yield
  yield console.log(r1);
  yield console.log(r2.title);
  yield console.log(r3.name);
};
//utilizamos esta constante "g" para devolver el valor de cada llamada
const g = anotherFunction(API);
g.next().value;
g.next().value;
g.next().value;
g.next().value;

en resumen:
yield se usa para pausar y reanudar una fucion generadora
esta se identifica con un asterisco antes del nombre ejemplo:

funcion* generator(array){
	for(let value of array){
		yield value;
	}
}

const it = generator(['pedro','juan','camilo','patricia']);
console.log(it.next().value) //'pedro'
console.log(it.next().value) //'juan'
console.log(it.next().value) //'camilo'
console.log(it.next().value) //'patricia'

el next() imprime dos cosas, el value (valor al lado derecho del yield)
y el done (verdadero o falso) sera verdadero si y solo si no hay mas yields dentro de la funcion generadora
para ello, veamos el siguiente ejemplo:

//Ahora si solo consologueamos el next , esto se tendria por respuesta:
console.log(it.next()) //{value:'pedro', done: false}
console.log(it.next()) //{value:'juan', done: false}
console.log(it.next()) //{value:'camilo', done: false}
console.log(it.next()) //{value:'patricia', done: false}
console.log(it.next()) //{value:undefined, done: true} 
//este ultimo siendo verdad pq ya no hay yields que mostrar

Reto con Promesas:

import fetch from "node-fetch";
const API = 'https://api.escuelajs.co/api/v1';

function* fetchData (urlApi) {
    while(true) yield fetch(urlApi)
                    .then(response => response.json())
                    .catch(error => console.error(error));
}

function getInfo () {
    fetchData(`${API}/products`).next().value
        .then(products => {
            console.log(products[0])
            return fetchData(`${API}/products/${products[0].id}`).next().value;
        })
        .then(product => {
            console.log(product.title);
            return fetchData(`${API}/categories/${product.category.id}`).next().value;
        })
        .then(category => {
            console.log(category.name);
        })
        .catch(error => console.error(error));
}

getInfo();

Reto con Async/Await

import fetch from "node-fetch";
const API = 'https://api.escuelajs.co/api/v1';

function* fetchData (urlApi) {
    while(true) yield fetch(urlApi)
                    .then(response => response.json())
                    .catch(error => console.error(error));
}

async function getInfo () {
    try {
        const products = await fetchData(`${API}/products`).next().value;
        const product  = await fetchData(`${API}/products/${products[0].id}`).next().value;
        const category = await fetchData(`${API}/categories/${product.category.id}`).next().value;

        console.log(product);
        console.log(product.title);
        console.log(category.name);
        
    } catch(error) {
        console.error(error);
    } 
}

getInfo();