0

How do I use co() wrapped functions to integrate with normal synchronous code?

For example I have co.wrapped this function that uses yield to call an async method on mongo:

let wrap = co.wrap(function* (collName) {
  debug("collName", collName);
  let collection = AppConfig.db.collection(collName);
  let res = yield collection.findOne({});
  debug("res", res);
  yield res;
});

which is being called with this:

//
class TopicsResponse {

  public static topics(bot, message) {
    let topic = wrap("Topics");
    debug("topic", topic);
    topic.then( function() {
      debug("topic.then", topic);
      bot.reply(message, "topics:" + topic.cname);
    });
  }
//
}

which gives a log like below:

TopicsResponse collName +3s Topics TopicsResponse topic +2ms Promise { <pending> } TopicsResponse res +1ms { _id: 56d6bdd93cf89d4082e1bd27, cname: 'nodejs', username: 'bob' } TopicsResponse topic.then +1ms Promise { undefined }

So inside the co.wrapped method, the res has real data: { cname: nodejs } etc. But what it returns/yields back is undefined.

I think this is something to do with the generator function yielding a promise..

I also tried just

yield collection.findOne({});

which returns

Promise { undefined }

Is it possible to use co this way to make what would be async code look/run like sync code? Other examples I've seen just put everything inside co() at the top level, eg http://mongodb.github.io/node-mongodb-native/2.1/api/Collection.html#find

Update, this works using promises:

let getTopic = co.wrap(function* (collName) {
  debug("collName", collName);
  let collection = AppConfig.db.collection(collName);
  let res = yield collection.findOne({});
  debug("res", res);  // prints correctly
  return res;
  // yield res;
});



//
class TopicsResponse {

  public static topics(bot, message) {
    let topic = getTopic("Topics");
    debug("topic", topic);
    topic.then( function(doc) {
      debug("doc", doc);
      debug("topic.then", topic);
      bot.reply(message, "topics:" + doc.cname);
    });
  }
//
}

But I want to push all the ugly promise wrapping .then() code into the library, and not have to sprinkle it all over my app...

dcsan
  • 7,487
  • 10
  • 50
  • 80
  • Did you mean `return res` in the generator function? – Bergi Mar 03 '16 at 19:21
  • actually yes, return res gives back the promise, but it's still a promise. i guess there's no way to get at the result (promise resolution?) – dcsan Mar 03 '16 at 19:27
  • `res` is not a promise - `findOne(…)` is one. `topic` will be another promise, and `doc` the result value. There's no other way to get at the result than wrapping your generator code in `co` or to use `then` explicitly. – Bergi Mar 03 '16 at 19:54

1 Answers1

0

No, once you "dirty" up your code with promises it has to be promises all the way (it's the same way with callbacks).

You have to wrap everything with a co( call. This will also behave this way with async functions when those land.

This is not an "artifact" or design issue - it is actually really useful as it can show you what parts of your code are asynchronous and what are not.

If you wrap everything in co you have explicit code - but not ugly code. You know exactly which methods do and which methods don't perform I/O.

Benjamin Gruenbaum
  • 246,787
  • 79
  • 474
  • 476