0

I am new to the Generator concept. My understanding is that if a function returns a Promise, then it can be used with yield. So I have a very small node.js script that looks like this:

Q.fcall(function*(){
  var url = "mongodb://" + config.host + ":" + config.port + "/" + config.db;
  var db = yield MongoClient.connect( url );
  var data = yield makeRequest();
  console.log( data );
  db.close();
});


function makeRequest(){
  var deferred = Q.defer();
  request({
      "method" : "GET",
      "url" : "....",
      "headers" : {
          "Accept" : "application/json",
          "user_key" : "...."
      }
  },function(err,data){
      if( err ){
          deferred.reject( err );
      }else{
          deferred.resolve( data );
      }
  });
  return deferred.promise;
}  

I know this works because I am porting it from the callback hell style to generator style. However, I do not see the data in console.log.

What do I need to change to make this work?

An SO User
  • 24,612
  • 35
  • 133
  • 221
  • *"My understanding is that if a function returns a Promise, then it can be used with `yield`."* Generators (and `yield`) have nothing to do with promises. They can be used together to implement something like `async/await`, but `yield` itself doesn't treat promises differently from any other value. – Felix Kling Mar 07 '16 at 07:25
  • This should answer your question: [What happens when promise is yielded in javascript?](http://stackoverflow.com/q/33947850/218196) – Felix Kling Mar 07 '16 at 07:27
  • @FelixKling thanks ! I was reading this http://stackoverflow.com/questions/17516952/trying-to-understand-generators-yield-in-node-js-what-executes-the-asynchron?rq=1 when you posted that :) – An SO User Mar 07 '16 at 07:29
  • @FelixKling I did a little digging around and changed `Q.fcall( )` to `co()` and it worked. So what does `co` exactly do? :) – An SO User Mar 07 '16 at 07:33
  • @LittleChild as far as I understand `co` it basically keeps calling `passedInGenerator.next()` until the `{done: true}` object is returned or an error occurs. – jmunsch Mar 07 '16 at 08:02
  • Also there is a decent and simple example here that shows the idea: http://stackoverflow.com/questions/21846390/getting-a-promises-value-via-yield-co – jmunsch Mar 07 '16 at 08:15
  • @jm_____ That solves it for me :) – An SO User Mar 07 '16 at 09:05

2 Answers2

1

Q.fcall is not suited to work with generator functions. You need to use the dedicated generator methods for that, in your case Q.spawn:

Q.spawn(function*() {
  var url = "mongodb://" + config.host + ":" + config.port + "/" + config.db;
  var db = yield MongoClient.connect( url );
  try {
    var data = yield makeRequest();
    console.log( data );
  } finally {
    db.close();
  }
});

Without a runner, the generator won't be automatically advanced asynchronously.

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

Consider using co that can wrap generators and make the callable. It returns promise.

const co = require('co');
const promisedGenerator = co.wrap(function* () {
  yield whatever1();
  yield whatever2();
  return databaseRequest(); 
});

promisedGenerator()
  .then(databaseResult => {
    console.log(databaseResult);
  });
dsdenes
  • 1,025
  • 6
  • 15