No tienes acceso a esta clase

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

Convierte tus certificados en títulos universitarios en USA

Antes: $249

Currency
$209

Paga en 4 cuotas sin intereses

Paga en 4 cuotas sin intereses
Suscríbete

Termina en:

18 Días
3 Hrs
4 Min
9 Seg

Generators

19/26
Recursos

Aportes 121

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().

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;

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.

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();

Aquí dejo el desarrollo que realicé para el desafío 😃 ![](

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.

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

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. 👨‍💻

Creo que, antes de "suicidarme" ..., mejor me vuelvo a pasar por este curso en unos meses ... Veo estudiantes con soluciones que (medio) entiendo al leerlas pero, Dios, nunca las hubiera podido crear con lo que yo se. Es serio, mis mayores 🎉Felicitaciones 🎉 a las personas que entienden este curso en profundidad. A mi me quedó tres tallas grande. Profe Oscar, mil disculpas, volveres por estos lugares cuando me sienta con más y mejores bases.
```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

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.

📣 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 ‘bajo 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 ‘bajo 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!
    .
# Solucion al reto! ```js // in this challenge we'll implement async / await with a generator function const url = "https://api.escuelajs.co/api/v1/products" async function fetchAPIData(urlAPI) { try{ const response = await fetch(urlAPI) if(!response.ok){ console.error(`HTTP error: ${response.status}`) } const data = await response.json() return data } catch (e) { console.error(e) } } // asynchronous function that returns a resolved promise from the fetched API async function* fetchGen(urlAPI) { yield await fetchAPIData(urlAPI) // first product yield await fetchAPIData(`${urlAPI}/1`) // second product const firstProduct = await fetchAPIData(`${urlAPI}/1`) if (firstProduct && firstProduct.category) { yield firstProduct.category.name } else { yield "Category not found" } // yielding category name of first product } // asynchronous generator function async function fetchData(urlAPI) { const dataGenerator = fetchGen(urlAPI) // we don't need an ' await ' statement here, due to the nature of the returned value of the generator for await (const data of dataGenerator) { console.log(`Recieved data: ${JSON.stringify(data, null, 2)}`) } //stringyfying in JSON format the data recieved, that way we can output it in the console } fetchData(url) ```
```js const API = "https://api.escuelajs.co/api/v1"; const postData = async (urlApi, data) => { try { /* throw new Error('SOME PROBLEM'); */ const res = await fetch(urlApi, { method: "POST", code: "cors", credentials: "same-origin", headers: { "Content-Type": "application/json", }, body: JSON.stringify(data), }); return res; } catch (error) { console.log(error); } }; const data = { title: "Arepa X1", price: 5, description: "X1", categoryId: 1, images: ["https://placeimg.com/640/480/any"], }; const arepas = [ { title: "Arepa 1", price: 5, description: "Arepa 1", categoryId: 1, images: ["https://placeimg.com/640/480/any"], }, { title: "Arepa 2", price: 5, description: "Arepa 2", categoryId: 1, images: ["https://placeimg.com/640/480/any"], }, { title: "Arepa 3", price: 5, description: "Arepa 3", categoryId: 1, images: ["https://placeimg.com/640/480/any"], }, { title: "Arepa 4", price: 5, description: "Arepa 4", categoryId: 1, images: ["https://placeimg.com/640/480/any"], }, { title: "Arepa 5", price: 5, description: "Arepa 5", categoryId: 1, images: ["https://placeimg.com/640/480/any"], }, ]; function* arepasGen(items) { for (const item of items) { yield item; } } const itAre = arepasGen(arepas); for (let i = 0; i < arepas.length; i++) { console.time("Tiempo"); postData(`${API}/products/`, itAre.next().value) .then((res) => res.json()) .then((data) => console.log(data)) .catch(() => console.log(error)); console.timeEnd("Tiempo"); } // Sin generador Yield // Enviadas en post => id 61, id: 62 // con generador Yield // Enviadas en post => id: 77 al id: 81 ```const API = "https://api.escuelajs.co/api/v1"; const postData = async (urlApi, data) => { try { */\* throw new Error('SOME PROBLEM'); \*/* const res = await fetch(urlApi, { method: "POST", code: "cors", credentials: "same-origin", headers: { "Content-Type": "application/json", }, body: JSON.stringify(data), }); return res; } catch (error) { console.log(error); }}; const data = { title: "Arepa X1", price: 5, description: "X1", categoryId: 1, images: \["https://placeimg.com/640/480/any"],}; const arepas = \[ { title: "Arepa 1", price: 5, description: "Arepa 1", categoryId: 1, images: \["https://placeimg.com/640/480/any"], }, { title: "Arepa 2", price: 5, description: "Arepa 2", categoryId: 1, images: \["https://placeimg.com/640/480/any"], }, { title: "Arepa 3", price: 5, description: "Arepa 3", categoryId: 1, images: \["https://placeimg.com/640/480/any"], }, { title: "Arepa 4", price: 5, description: "Arepa 4", categoryId: 1, images: \["https://placeimg.com/640/480/any"], }, { title: "Arepa 5", price: 5, description: "Arepa 5", categoryId: 1, images: \["https://placeimg.com/640/480/any"], },]; function\* arepasGen(items) { for (const item of items) { yield item; }}const itAre = arepasGen(arepas);for (let i = 0; i < arepas.length; i++) { console.time("Tiempo"); postData(`${API}/products/`, itAre.next().value) .then((res) => res.json()) .then((data) => console.log(data)) .catch(() => console.log(error)); console.timeEnd("Tiempo");} *// Sin generador Yield// Enviadas en post => id 61, id: 62* *// con generador Yield// Enviadas en post => id: 77 al id: 81*
![](https://static.platzi.com/media/user_upload/image-c4df50d5-005b-487c-8c97-695f762378c8.jpg)
```js 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(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}`); yield products[0]; yield product.title; yield category.name; } const generator = anotherFunction(API); // Obtén el iterador del generador async function experimento() { console.log('Entro'); const result = await generator.next(); // Llama a `next()` para obtener el siguiente valor console.log('Se obtuvo Rpta'); console.log(result.value); // Accede al valor yield usando `result.value` } experimento(); // Primera llamada: obtiene products[0] experimento(); // Segunda llamada: obtiene product.title experimento(); // Tercera llamada: obtiene category.name ```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(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}`);   yield products\[0];  yield product.title;  yield category.name;} const generator = anotherFunction(API); // Obtén el iterador del generador async function experimento() {  console.log('Entro');  const result = await generator.next(); // Llama a `next()` para obtener el siguiente valor  console.log('Se obtuvo Rpta');  console.log(result.value); // Accede al valor yield usando `result.value`} experimento(); // Primera llamada: obtiene products\[0]experimento(); // Segunda llamada: obtiene product.titleexperimento(); // Tercera llamada: obtiene category.name
Buenas noches, la siguiente es para compartir con ustedes mi aporte. Muchas gracias por su atención. ```js 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) function* iterate(array){ for (let value of array){ yield value } } const it = iterate(['oscar', 'omar', 'ana', 'lucía', 'juan']) for (let value of it){ console.log(value) } ```
Mi solución : ```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; } function* iterateProducts(array) { for (let value of array){ yield value } } const anotherFunction = 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}`); const it = iterateProducts([products, product.title, category.name]) console.log(it.next().value); console.log(it.next().value); console.log(it.next().value); } catch (error){ console.error(error) } } anotherFunction(API) ```
![](https://static.platzi.com/media/user_upload/code-98b6a926-d9a0-42d3-9815-0d4a1857e033.jpg)

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 donevalue 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)

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 ‘next()’ del iterador es llamado, el cuerpo de la función generadora se ejecuta hasta la primera expresión ‘yield’ , la cual tiene el valor que será retornado.
.
next(), retorna un objeto con la propiedad ‘value’ que contiene el valor bajo el operador ‘yield’ y otra propiedad ‘done’ 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 “generator” 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…of 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 “generadores 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 “Generators” 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** “yield”** 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 “node-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…of 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 “next()”

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();