pjlamb12 pjlamb12 - 2 months ago 12
Javascript Question

Looping Through a JavaScript Generator Function

I'm trying to use a JavaScript generator function to get data from a database. But each step depends on the data that comes before it. I used an example from Wes Bos's ES6.io course, and in that, it does something similar and looks like

function ajax(url) {
fetch(url).then(data => data.json()).then(data => dataGen.next(data))
}

function* steps() {
console.log('fetching beers');
const beers = yield ajax('http://api.react.beer/v2/search?q=hops&type=beer');
console.log(beers);

console.log('fetching user');
const user = yield ajax('https://api.github.com/users/[user]');
console.log(user);

console.log('fetching fat joe');
const fatJoe = yield ajax('https://api.discogs.com/artists/51988');
console.log(fatJoe);
}

const dataGen = steps();
dataGen.next(); // kick it off


This works perfectly. The problem is that this depends on
dataGen
being globally available. I need to do all this inside a function. How can I call that
dataGen
in a loop but from another function? I'm looking for something similar to this:

function ajax(url) {
fetch(url).then(data => data.json()).then(data => dataGen.next(data))
}

function* steps() {
console.log('fetching beers');
const beers = yield ajax('http://api.react.beer/v2/search?q=hops&type=beer');
console.log(beers);

console.log('fetching user');
const user = yield ajax('https://api.github.com/users/[user]');
console.log(user);

console.log('fetching fat joe');
const fatJoe = yield ajax('https://api.discogs.com/artists/51988');
console.log(fatJoe);
}

function getInfo() {
const dataGen = steps();
for (const data of dataGen) {
console.log(data);
}
}


the
getInfo()
call ideally would be able to kick off the generator and be able to pass the data from each step on to the next one so that the data gets filled out correctly.

Any suggestions? I can use ES6 functions or functionality, but nothing higher.

Here's the output in the browser console for what happens when I try to do the second option, the one I'd love to get working:

enter image description here

Answer

The tricky part here is that the ajax function doesn't return anything, and if it did, it doesn't return the data right away.

So, to do what you are looking for, we have to move the promise logic into our loop. We can get rid of ajax() entirely and just use fetch directly:

function* steps() {
    const beers = yield fetch('http://api.react.beer/v2/search?q=hops&type=beer');
    const user = yield fetch('https://api.github.com/users/wesbos');
    const fatJoe = yield fetch('https://api.discogs.com/artists/51988');
}

function getInfo() {
  const dataGen = steps();
  for(const promise of dataGen) {
    promise.then(data => data.json()).then(data => {
      console.log(data);
      dataGen.next(data);
    });
  }
}

getInfo();