Search code examples
javascriptecmascript-6generatoryield

How to pass value from first yield to next ones in ES6 generator?


I searched for real cases ES6 generators and didn't find proper explanation. I am trying to understand this first Promise scenario.

Let's say we have 2 rest apis: getUser and getUserComments

We wan't to create a linear code structure avoiding nested then callback functionalities. So ...

Define mocked apis

function getUser () {
    return new Promise(function(resolve, reject) {
       return setTimeout(function() { resolve({id: 1, label: 'John'}); }, 200);
    });
}

function getUserComments(userId) {
    return new Promise(function(resolve, reject) {
      return setTimeout(function() {resolve({comments: 'comments', userId: userId}); }, 200);
    });
}

Define generator

function* generator () {
  yield getUser();
  yield getUserComments(userId); // userId represents data from first request / first yield how should I pass it ?!
}

var g = generator();
var first  = g.next(1);
var second = g.next(2);

How can I get the response from first yield (yield getUser()) and pass it to the next yield (yield getUserComments(userId)) ?


Solution

  • You could just assign yielded result to variable:

    The next() method also accepts a value which can be used to modify the internal state of the generator. A value passed to next() will be treated as the result of the last yield expression that paused the generator. (From MDN, Advanced generators)

    Then since you are dealing with Promises it makes sense to use async/await to unwrap it to value.

    Try this (I corrected setTimeout parameters a bit):

    async function getUser() {
      return new Promise(function(resolve, reject) {
        setTimeout(resolve, 0, {
          id: 1,
          label: 'John'
        })
      })
    };
    
    async function getUserComments(user) {
      return new Promise(function(resolve, reject) {
        setTimeout(resolve, 0, {
          ...user,
          comments: 'comments',
        }, 'userComments');
      });
    }
    
    function* generator () {
      const user = yield getUser();
      yield getUserComments(user);
    }
    
    (async function () {
      const g = generator();
      const user = await g.next().value
      const comments = await g.next(user).value
    
      console.log(comments)
    })()