How to combine ES6 Generators with Promises

2019-06-08 15:18发布

问题:

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

回答1:

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!



回答2:

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++;
  }
});