1

I'm trying to conceptually understand how ES6 Generators can make async code more streamlined. Here's a contrived example:

  1. I have a function called getGitHubUser which takes a username and returns a Promise which ultimately resolves to the github user's info.
  2. I have an array of usernames.
  3. I'd like to call getGitHubUser with the first username and when that Promise resolves, I want to call getGitHubUser with the next username, and continue this until I've iterated through all the usernames.

I have a working implementation but I'm more curious on how I can leverage generators to make this better.

var getGitHubUser = (user) => {
  // using jQuery's $.get
  return Promise.resolve($.get("https://api.github.com/users/" + user));
};

var usernames = ["fay-jai", "jyek", "Maestro501", "jaclyntsui"];

getGitHubUser(usernames[0])
  .then((result) => {
    console.log(result); // fay-jai
    return getGitHubUser(usernames[1]);
  })
  .then((result) => {
    console.log(result); // jyek
    return getGitHubUser(usernames[2]);
  })
  .then((result) => {
    console.log(result); // Maestro501
    return getGitHubUser(usernames[3]);
  })
  .then((result) => {
    console.log(result); // jaclyntsui
  });
wmock
  • 5,382
  • 4
  • 40
  • 62
  • 1
    I don't think generators are of any help here. You could simply iterate over the array instead of "manually" chaining the `.then` calls. – Felix Kling Nov 01 '15 at 21:56
  • Is that true if each subsequent result depends on the previous Promise call? In my example, I'm currently just logging out the result but in the event that the next Promise call depends on the previous call resolving, then I would need to manually chain it, right? – wmock Nov 01 '15 at 21:59
  • 1
    No. Example: `var p = Promise.resolve(); data.forEach(d => (p = p.then(result => someAsyncCall(d, result))));`. You just keep calling `p = p.then(...)` in the loop. This chains the new promise to the previous promise. – Felix Kling Nov 01 '15 at 22:06
  • Thanks for providing the example @FelixKling! In what situations would generators be useful for asynchronous code? – wmock Nov 01 '15 at 22:43
  • 1
    This may be interesting to you: http://davidwalsh.name/async-generators. – Felix Kling Nov 01 '15 at 22:50
  • related: [ES6 generators: yield promise](http://stackoverflow.com/a/30412920/1048572) – Bergi Nov 02 '15 at 13:19

2 Answers2

2

If you would like to get the ide of how it works, consider this good article.

If you're lookign for some woring solution, there are lots of libraries to handle callback hell (becaise basically this is the main reason why people are looking for more elegant solutions).

Q.spawn was already given a brief description by @user890255 in his answer, but threre are others. For example, co which I like most:

var request = require('superagent');
co(function* () {
  var data = [];
  for(var i = 0; i < usernames.length; i++){
    data.push(yield request.get("https://api.github.com/users/" + usernames[i]));
  }
  return data;
}).then((value) => {
  console.log(value);
}, (err) => {
   console.error(err.stack);
});

As you can see, co always returns a promise, which is very handy.

And minimalistic (due to a small file size, I suppose) vo

var request = require('superagent');

vo(function* () {
  var data = [];
  for(var i = 0; i < usernames.length; i++){
    data.push(yield request.get("https://api.github.com/users/" + usernames[i]));
  }
  return data;
})((err, res) => {
  console.log(res);
});

As you can see, the code in the generator function s pretty much the same.

Cheers!

Alexander Mikhalchenko
  • 4,525
  • 3
  • 32
  • 56
1

This is how you do it using Q. Read also Harmony generators and promises for Node.js async fun and profit and JavaScript Promises.

var usernames = ["fay-jai", "jyek", "Maestro501", "jaclyntsui"];
Q.spawn(function *(){
  var index = 0;
  while (index < usernames.length){
    console.log(yield Promise.resolve($.get("https://api.github.com/users/" + usernames[index])));
    index++;
  }
});
user890255
  • 458
  • 5
  • 9