0

I would like to know if it is possible to return successively-yielded values as an array when the generator is done. This is what I have tried so far, where I add a return statement at the end of the generator and attempt to destructure the output:

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

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

  const wes = yield ajax('https://api.github.com/users/wesbos');

  const fatJoe = yield ajax('https://api.discogs.com/artists/51988');

  return [beers, wes, fatJoe]
}

const dataGen = steps();
const [beers, wes, fatJoe] = dataGen.next(); // kick it off

However, none of the values are returned:

Uncaught ReferenceError: beers is not defined
Uncaught ReferenceError: wes is not defined
Uncaught ReferenceError: fatJoe is not defined
Michał Perłakowski
  • 88,409
  • 26
  • 156
  • 177
Robert Valencia
  • 1,752
  • 4
  • 20
  • 36
  • You have to call next until you get to the return statement before you get the returned array – Andrew Li Jun 03 '17 at 18:00
  • I see. Should I also use `yield` instead of `return` for the last statement? – Robert Valencia Jun 03 '17 at 18:01
  • The requested URL's have issues. What is expected result? The resulting `Promise` value of `fetch()` call? Why do you not use `Promise.all()`? – guest271314 Jun 03 '17 at 18:17
  • @guest271314 if I console log beers, wes, and fatJoe, remove `return [beers, wes, fatJoe]`, and replace `const [beers, wes, fatJoe] = dataGen.next();` with `dataGen.next();`, I get 3 Objects. Also, this is based on an online course, and I am just modifying the existing code. – Robert Valencia Jun 03 '17 at 18:21

2 Answers2

1

If interpret Question correctly you can use yield*, pass steps() call to Promise.all(), .then()

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Generators</title>
</head>
<body>
<script>

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

  function* steps() {
    yield* [
             ajax('data:application/json,[1]')
             , ajax('data:application/json,[2]')
             , ajax('data:application/json,[3]')
           ];
  }

  // kick it off
  Promise.all(steps())
  .then(([beers, wes, fatJoe]) => 
    console.log(beers, wes, fatJoe)
  )
</script>
</body>
</html>

Or Promise.all() without generator function

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Generators</title>
</head>
<body>
<script>

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

  function steps() {
    return [
             ajax('data:application/json,[1]')
             , ajax('data:application/json,[2]')
             , ajax('data:application/json,[3]')
           ];
  }

  // kick it off
  Promise.all(steps())
  .then(([beers, wes, fatJoe]) => 
    console.log(beers, wes, fatJoe)
  )
</script>
</body>
</html>
guest271314
  • 1
  • 15
  • 104
  • 177
1

Stop using generators as a replacement for async/await. If you want to do that, you need to use a proper asynchronous runner such as the co library or Bluebird.coroutine. But their era is the past now, async/await is readily available in recent browsers (and in transpilers anyway)!

function ajax(url) {
  return fetch(url).then(data => data.json());
//^^^^^^
}

async function steps() {
  const beers = await ajax('http://api.react.beer/v2/search?q=hops&type=beer');
  const wes = await ajax('https://api.github.com/users/wesbos');
  const fatJoe = await ajax('https://api.discogs.com/artists/51988');

  return [beers, wes, fatJoe];
}

const dataPromise = steps(); // kick it off
dataPromise.then(([beers, wes, fatJoe]) => {
  console.log(…); // use results here
});

(or alternatively await dataPromise in another async function)

Bergi
  • 630,263
  • 148
  • 957
  • 1,375