Code Monkey home page Code Monkey logo

co's Introduction

co

Gitter NPM version Build status Test coverage Downloads

Generator based control flow goodness for nodejs and the browser, using promises, letting you write non-blocking code in a nice-ish way.

Co v4

[email protected] has been released, which now relies on promises. It is a stepping stone towards the async/await proposal. The primary API change is how co() is invoked. Before, co returned a "thunk", which you then called with a callback and optional arguments. Now, co() returns a promise.

co(function* () {
  var result = yield Promise.resolve(true);
  return result;
}).then(function (value) {
  console.log(value);
}, function (err) {
  console.error(err.stack);
});

If you want to convert a co-generator-function into a regular function that returns a promise, you now use co.wrap(fn*).

var fn = co.wrap(function* (val) {
  return yield Promise.resolve(val);
});

fn(true).then(function (val) {

});

Platform Compatibility

co@4+ requires a Promise implementation. For versions of node < 0.11 and for many older browsers, you should/must include your own Promise polyfill.

When using node 0.10.x and lower or browsers without generator support, you must use gnode and/or regenerator.

When using node 0.11.x, you must use the --harmony-generators flag or just --harmony to get access to generators.

Node v4+ is supported out of the box, you can use co without flags or polyfills.

Installation

$ npm install co

Associated libraries

Any library that returns promises work well with co.

  • mz - wrap all of node's code libraries as promises.

View the wiki for more libraries.

Examples

var co = require('co');

co(function *(){
  // yield any promise
  var result = yield Promise.resolve(true);
}).catch(onerror);

co(function *(){
  // resolve multiple promises in parallel
  var a = Promise.resolve(1);
  var b = Promise.resolve(2);
  var c = Promise.resolve(3);
  var res = yield [a, b, c];
  console.log(res);
  // => [1, 2, 3]
}).catch(onerror);

// errors can be try/catched
co(function *(){
  try {
    yield Promise.reject(new Error('boom'));
  } catch (err) {
    console.error(err.message); // "boom"
 }
}).catch(onerror);

function onerror(err) {
  // log any uncaught errors
  // co will not throw any errors you do not handle!!!
  // HANDLE ALL YOUR ERRORS!!!
  console.error(err.stack);
}

Yieldables

The yieldable objects currently supported are:

  • promises
  • thunks (functions)
  • array (parallel execution)
  • objects (parallel execution)
  • generators (delegation)
  • generator functions (delegation)

Nested yieldable objects are supported, meaning you can nest promises within objects within arrays, and so on!

Promises

Read more on promises!

Thunks

Thunks are functions that only have a single argument, a callback. Thunk support only remains for backwards compatibility and may be removed in future versions of co.

Arrays

yielding an array will resolve all the yieldables in parallel.

co(function* () {
  var res = yield [
    Promise.resolve(1),
    Promise.resolve(2),
    Promise.resolve(3),
  ];
  console.log(res); // => [1, 2, 3]
}).catch(onerror);

Objects

Just like arrays, objects resolve all yieldables in parallel.

co(function* () {
  var res = yield {
    1: Promise.resolve(1),
    2: Promise.resolve(2),
  };
  console.log(res); // => { 1: 1, 2: 2 }
}).catch(onerror);

Generators and Generator Functions

Any generator or generator function you can pass into co can be yielded as well. This should generally be avoided as we should be moving towards spec-compliant Promises instead.

API

co(fn*).then( val => )

Returns a promise that resolves a generator, generator function, or any function that returns a generator.

co(function* () {
  return yield Promise.resolve(true);
}).then(function (val) {
  console.log(val);
}, function (err) {
  console.error(err.stack);
});

var fn = co.wrap(fn*)

Convert a generator into a regular function that returns a Promise.

var fn = co.wrap(function* (val) {
  return yield Promise.resolve(val);
});

fn(true).then(function (val) {

});

License

MIT

co's People

Contributors

a8m avatar alexmingoia avatar dead-horse avatar fengmk2 avatar gitter-badger avatar hemanth avatar island205 avatar jonathanong avatar juliangruber avatar madbence avatar matthewmueller avatar navaru avatar pana avatar patrickjs avatar plievone avatar richayotte avatar saadq avatar sahat avatar shimont avatar swolfand avatar takayuky avatar timoxley avatar tj avatar tootallnate avatar tricknotes avatar welefen avatar willconant avatar yorkie avatar yuchi avatar zensh avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

co's Issues

Unexpected token *

Trying to run the examples but I keep getting and "Unexpected token *" error for "co(function *(){"

Please advise if there is something special that I need to do to get this to run.

uncaught from generator

co may be outdated or something but I ran across a case where a generator's error was not caught properly. I'll try and repro in a bit

Leading or trailing thunks

It might clarify Readme.md examples if the difference between two kinds of thunks would be made clearer. Currently the thunks are introduced as trailing kind:

function read(...args) {
  return function thunk(cb) {
    // start work, cb(err, result) later
  }
}

but functions from thunkify start the work already on the leading edge:

function read(...args) {
  // start work, save result later
  return function thunk(cb) {
    // cb(err, result) or when result ready
  }
}

This difference helps to understand when work can start concurrently (in the event loop sense) even before yielding.

Currently the frontpage examples mix both styles, confusing where the concurrency comes in each case. And the example with "3 concurrent requests at a time" and "9 concurrent requests" won't do what it says, because there are those sequential yields in the *results() generator, whatever style the thunks are.

noob question: what does co do? i.e: running body of examples without wrapping in co-generator runs just fine

This is undoubtedly a noob-question, but what does wrapping a body with yields in a co generator provide for extra funcitonality?

I mean the following (lifted as an example from the co github homepage) works just fine without wrapping in a co -generator (if that's the correct nomenclature):

 var co = require('co');
 var fs = require('fs');

 function read(file) {
   return function(fn){
     fs.readFile(file, 'utf8', fn);
   }
 }

 //superfluous co?
 co(function *(){
   var a = yield read('.gitignore');
   var b = yield read('Makefile');
   var c = yield read('package.json');
   return [a, b, c];
 })()

//this works fine as well, without the return obviously
var a = yield read('.gitignore');
var b = yield read('Makefile');
var c = yield read('package.json');
console.log([a, b, c]);

Is it for chaining or error-bubbling or something?

yieldable objects

found destructuring pretty annoying with arrays. i want to do the following:

var obj = yield {
  a: get('a'),
  b: get('b'),
  c: get('c')
}

Example doesn't work

Still investigating why, but this

var thunkify = require('thunkify');
var request = require('superagent');
var co = require('co')

var get = thunkify(request.get);

function *results () {
  var a = yield get('http://google.com')
  var b = yield get('http://yahoo.com')
  var c = yield get('http://ign.com')
  return [a.status, b.status, c.status]
}

co(function *() {
  // 3 concurrent requests at a time
  var a = yield results;
  var b = yield results;
  var c = yield results;
  console.log(a, b, c);

  // 9 concurrent requests
  console.log(yield [results, results, results]);
})()

doesn't work.

v0.11.8

Date objects don't survive yield

Apparently Date objects don't retain their value in objects passed through an object yield. Check this out:

var assert = require('assert')
var co = require('co')

co(function* () {
  var foo = {
    now: new Date
  }

  var bar = yield foo

  assert(foo.now === bar.now)
})()

release plzzz

or move to org or add me as maintainer. working on some stuff and co's api being in limbo is no fun ahah.

i can fix all of the koajs too if u give me npm rights

make toThunk public?

before, the join for arrays was public, which didn't make sense to me. how about making toThunk public?

co-wrap

not too useful in here since you don't want to require co all the time

`Error: Generator is already running` when no callback provided

Test case:

it('should rethrow an error if no callback is provided', function (done) {
  function onUncaughtException (err) {
    err.message.should.equal('fail');
    process.removeListener('uncaughtException', onUncaughtException);
    done();
  }

  process.on('uncaughtException', onUncaughtException);

  co(function * () {
    yield function (cb) {
      cb(new Error('fail'), null)
    }
  })()
})

Some other things I've tried:

var co = require('co')

function * generator () {
  throw new Error('error')
}

function syncThunk (cb) {
  cb(new Error('error'), null)
}

function asyncThunk (cb) {
    process.nextTick(cb.bind(null, new Error('error')))
}

/**
 * Async thunk — works as expected (throws `error`)
 */

co(function * () {
  yield asyncThunk
})()


/**
 * Sync thunk — throws `Error: Generator is already running` 
 */

co(function * () {
  yield syncThunk
})()


/**
 * but this works 
 */

co(function * () {
  yield syncThunk
})(console.log)


/**
 * Generator — throws `Error: Generator is already running` 
 */

co(function * () {
  yield generator
})()

/**
 * but this works 
 */

co(function * () {
  yield generator
})(console.log)


/**
 * No nesting - also works
 */

co(function * () {
  throw Error('error')
})()

No documentation on asterisks

There needs to be documentation on asterisks, in one of the first paragraphs of the main Readme.

It is not at all clear to anyone new to generators in javascript what they are for, or that they are associated in any way with something called "generators", whether they represent new syntax or not, etc.

The status quo results in unnecessary wasted time for many people.

Here's some documentation about the topic, but even after reading it, I'm still unclear as to whether these symbols are necessary or not.

Memory leak in co?

I was using co in one of my scripts and I noticed that the program crashed several times. Here's a simple example demonstrating potential memory leak in co (it's just a slight modification from generator-join.js):

var request = require('request');
var thunk = require('thunkify');
var co = require('co');
var join = co.join;

var get = thunk(request.get);

// measure response time N times

function *latency(url, times) {
  var ret = [];

  while (times--) {
    var start = new Date;
    yield get(url);
    ret.push(new Date - start);
  }

  return ret;
}

// run each test in sequence

co(function *(){
  var a;
  for (var i = 0; i < 50; i++) {
    a = yield latency('http://google.com', 5);
    console.log(a, process.memoryUsage());
  }
})();

And here's the corresponding output:

[ 398, 232, 292, 319, 337 ] { rss: 25387008, heapTotal: 17734144, heapUsed: 9919432 }
[ 337, 357, 207, 259, 227 ] { rss: 28585984, heapTotal: 18766080, heapUsed: 9759712 }
[ 209, 233, 210, 211, 245 ] { rss: 30932992, heapTotal: 18766080, heapUsed: 11381208 }
[ 245, 254, 260, 243, 240 ] { rss: 33181696, heapTotal: 18766080, heapUsed: 7599944 }
[ 239, 219, 268, 213, 280 ] { rss: 34131968, heapTotal: 18766080, heapUsed: 9280024 }
[ 266, 276, 259, 222, 242 ] { rss: 35422208, heapTotal: 18766080, heapUsed: 10839816 }
[ 245, 213, 259, 207, 252 ] { rss: 36618240, heapTotal: 18766080, heapUsed: 10152784 }
[ 240, 1334, 242, 208, 226 ] { rss: 37371904, heapTotal: 18766080, heapUsed: 11675720 }
[ 247, 210, 206, 278, 219 ] { rss: 40656896, heapTotal: 28186624, heapUsed: 12007080 }
[ 221, 298, 287, 209, 246 ] { rss: 41672704, heapTotal: 29206528, heapUsed: 13715048 }
[ 216, 251, 214, 215, 334 ] { rss: 44761088, heapTotal: 29206528, heapUsed: 7978664 }
[ 352, 446, 309, 398, 286 ] { rss: 45621248, heapTotal: 29206528, heapUsed: 9815936 }
[ 410, 222, 247, 294, 307 ] { rss: 46465024, heapTotal: 29206528, heapUsed: 11446368 }
[ 365, 254, 305, 289, 311 ] { rss: 47640576, heapTotal: 29206528, heapUsed: 12994936 }
[ 276, 212, 247, 213, 215 ] { rss: 49844224, heapTotal: 29206528, heapUsed: 14619616 }
[ 273, 221, 244, 338, 276 ] { rss: 51908608, heapTotal: 29206528, heapUsed: 16081152 }
[ 235, 225, 265, 216, 226 ] { rss: 54247424, heapTotal: 30238464, heapUsed: 13051216 }
[ 660, 251, 219, 205, 223 ] { rss: 54870016, heapTotal: 30238464, heapUsed: 14686608 }
[ 214, 213, 227, 267, 211 ] { rss: 55537664, heapTotal: 30238464, heapUsed: 16160904 }
[ 245, 274, 240, 301, 234 ] { rss: 55877632, heapTotal: 29218560, heapUsed: 8875536 }
[ 208, 225, 205, 242, 249 ] { rss: 56360960, heapTotal: 29218560, heapUsed: 10474704 }
[ 240, 291, 234, 247, 277 ] { rss: 56872960, heapTotal: 29218560, heapUsed: 12106416 }
[ 246, 250, 213, 222, 223 ] { rss: 57290752, heapTotal: 29218560, heapUsed: 13655184 }
[ 246, 232, 255, 208, 245 ] { rss: 57655296, heapTotal: 29218560, heapUsed: 15251648 }
[ 215, 207, 232, 243, 253 ] { rss: 57860096, heapTotal: 29218560, heapUsed: 16794152 }
[ 252, 211, 278, 225, 275 ] { rss: 58736640, heapTotal: 45995776, heapUsed: 13843536 }
[ 244, 359, 242, 270, 256 ] { rss: 60297216, heapTotal: 47015680, heapUsed: 15564072 }
[ 270, 231, 216, 246, 336 ] { rss: 61546496, heapTotal: 47015680, heapUsed: 17189608 }
[ 236, 1437, 348, 335, 333 ] { rss: 63066112, heapTotal: 47015680, heapUsed: 9346624 }
[ 364, 281, 319, 310, 293 ] { rss: 63782912, heapTotal: 47015680, heapUsed: 10925880 }
[ 402, 701, 269, 226, 328 ] { rss: 64053248, heapTotal: 47015680, heapUsed: 12542152 }
[ 249, 260, 214, 292, 223 ] { rss: 64483328, heapTotal: 47015680, heapUsed: 14088944 }
[ 223, 292, 325, 244, 214 ] { rss: 64905216, heapTotal: 47015680, heapUsed: 15694472 }
[ 255, 249, 244, 230, 292 ] { rss: 65994752, heapTotal: 47015680, heapUsed: 17285168 }
[ 296, 226, 219, 275, 241 ] { rss: 67985408, heapTotal: 47015680, heapUsed: 18943416 }
[ 279, 219, 234, 246, 294 ] { rss: 69865472, heapTotal: 47015680, heapUsed: 20473888 }
[ 263, 221, 277, 261, 238 ] { rss: 72028160, heapTotal: 48047616, heapUsed: 9039320 }
[ 318, 352, 333, 208, 257 ] { rss: 72278016, heapTotal: 48047616, heapUsed: 10621104 }
[ 331, 287, 233, 227, 229 ] { rss: 72732672, heapTotal: 48047616, heapUsed: 12236560 }
[ 255, 272, 269, 259, 210 ] { rss: 73031680, heapTotal: 48047616, heapUsed: 13791800 }
[ 249, 232, 257, 236, 321 ] { rss: 73203712, heapTotal: 48047616, heapUsed: 15396432 }
[ 260, 250, 258, 274, 250 ] { rss: 73388032, heapTotal: 48047616, heapUsed: 16952208 }
[ 226, 1348, 267, 277, 258 ] { rss: 74506240, heapTotal: 48047616, heapUsed: 18574000 }
[ 224, 240, 247, 227, 216 ] { rss: 76230656, heapTotal: 48047616, heapUsed: 20116352 }
[ 225, 230, 237, 245, 281 ] { rss: 78012416, heapTotal: 48047616, heapUsed: 21707464 }
[ 250, 237, 266, 249, 259 ] { rss: 79835136, heapTotal: 48047616, heapUsed: 9418856 }
[ 229, 226, 275, 259, 241 ] { rss: 79966208, heapTotal: 48047616, heapUsed: 10952808 }
[ 228, 294, 322, 210, 255 ] { rss: 80150528, heapTotal: 48047616, heapUsed: 12421584 }
[ 210, 210, 230, 244, 203 ] { rss: 80453632, heapTotal: 48047616, heapUsed: 13924544 }
[ 220, 239, 253, 221, 252 ] { rss: 80809984, heapTotal: 48047616, heapUsed: 15441368 }

As you can see, the size of rss and heapTotal keep increasing. Does anybody have an insight on this? I'm not sure if there is a memory leak in co or in my example script above.

changing behavior based on tick seems sketchy

Currently co will change it's error handling behavior based on if you do:

co(function *() { ... })

vs.

var go = co(function *() { ... });
go(function(err) { ... });

However, co will get it wrong if the generator function finished before go is called.

var go = co(function *() { ... });

setTimeout(function() {
  go(function(err) { ... });
}, 5000);

This may lead to unexpected errors. I personally think co should always return a function to be called when ready. Making this change would result in the first example looking like this:

co(function *() { ... })()

LICENSE?

You need to put the actual text of the MIT license somewhere

trace() support

just realized co would be an excellent point of entry for profiling async boundaries with jstrace

Pass arguments into the generator

Not sure if this is possible with generators, but it'd be nice to be able to do something like this:

var runner = co(function *(cmd) {
  var res = yield exec(cmd);
  return res;
});

runner('pwd', function(err, res) {
  if (err) throw err;
  console.log(res);
});

Maximum call stack size exceeded

I currently can't provide the code, that provoked this error (business stuff), but I just want to let you know, that this happens.

/opt/aulito/bot/node_modules/co/index.js:92
          ret.value.call(ctx, function(){
                                      ^
RangeError: Maximum call stack size exceeded
    at /opt/aulito/bot/node_modules/co/index.js:92:39
    at next (/opt/aulito/bot/node_modules/co/index.js:69:18)
    at /opt/aulito/bot/node_modules/co/index.js:95:18
    at next (/opt/aulito/bot/node_modules/co/index.js:69:18)
    at /opt/aulito/bot/node_modules/co/index.js:95:18
    at next (/opt/aulito/bot/node_modules/co/index.js:69:18)
    at /opt/aulito/bot/node_modules/co/index.js:95:18
    at next (/opt/aulito/bot/node_modules/co/index.js:69:18)
    at /opt/aulito/bot/node_modules/co/index.js:95:18
    at next (/opt/aulito/bot/node_modules/co/index.js:69:18)

uncaught exceptions in nested generators won't throw in callback fn, co(gen)(fn)

Here's how to reproduce it:

var co = require('co');

co(function *() {
  yield function *() {
    req + 'hi'; // ReferenceError: req is not defined
    return req;
  }
})(function(err) {
  throw err; // error doesn't throw, it simply won't print anything after this
  console.log(err); // if I remove throw err, it will log [ReferenceError: req is not defined]
  console.log('hi');
});

This is inconsistent with the non-nested example:

var co = require('co');

co(function *() {
  req + 'hi';
})(function(err) {
  throw err; // properly throws
});

Support AGen specification for asynchronous generators

To generate discussion, feedback and achieve interoperability:

@Raynos and I put together the AGen specification with feedback from @creationix for asynchronous generators, generators + asynchrony (e.g., promises, continuables, etc...) which we're using in our own libraries (gens) to create a cohesive specification for asynchronous generator interoperability.

Some highlights:

  • Asynchrony agnostic: implementor/user could support promises, thunks, or something new and exotic, but must support yielding on generator objects.
  • Support for serial (vanilla yield) or parallel (yield [...]) execution.
  • Separation of Errors and Exceptions

Why not support yield undefind?

I offen get this error

Error: yield a function, promise, generator, array, or object?

And it is hard to trace the problem, mostly it is happen when I yield a undefined value, so why not just allow to yield undefind.

Below code explain a case that how it happen.

function load(x){
   return function(callback) {
     db.load(x, callback);
   }
}
function loadFields(obj) {
   if(!obj) return;
   obj.x = load(obj.x);
   obj.y = load(obj.y);
   obj.z = load(obj.z);
   return obj;
}

co(function*() {
  var obj = yield getFromDb(id) // should return {x:1, y: 2, z:3};
  obj = yield loadFields(obj); // If obj is undefind, this line will occurs a Error, and hard to trace to this line.
})()

undefined is not a function on GeneratorFunction that has had bind called on it

I'm not sure if this is by design, but I've noticed that if you have a generator function that has had the bind method called on it co dies with an 'undefined is not a function' error. Looking at the line (83:21 of co/index.js) it's attempting to call a method next on gen.

Here's an example:

'use strict';

let co = require('co');

function BindFailer() {
  this.message = 'FAIL';
}

BindFailer.prototype.async = function async() {
  return new Promise((function (resolve, reject) {
    setTimeout((function () { resolve(this.message); }).bind(this), 3000);
  }).bind(this));
};

let b = new BindFailer();

function* failedGenerator() {
  let msg = yield this.async();
  console.log(msg);
};

function* successGenerator() {
  let msg = yield b.async();
  console.log(msg);
};

// Will complete successfully
co(successGenerator)();

// This will fail because bind is called on the method
// and the method is no longer considered a
// GeneratorFunction, but the return value of the method
// is still an iterator
co(failedGenerator.bind(b))();

Obviously the above is a ridiculous example, but it gets the job done. Is there a reason as to why co does not support this functionality?

In all honesty I'm migrating an application from q.spawn to co and have run into this because the former doesn't cause an exception on bound generators.

Am I doing something taboo? To be honest I'm a bit surprised that using the native bind method changes the constructor of a function from GeneratorFunction to Function which I think is the main reason why co is failing.

And here's the stack trace:

TypeError: undefined is not a function
    at next (/Users/mbrio/Desktop/prom/node_modules/co/index.js:83:21)
    at /Users/mbrio/Desktop/prom/node_modules/co/index.js:56:5
    at Object.<anonymous> (/Users/mbrio/Desktop/prom/simple.js:34:28)
    at Module._compile (module.js:449:26)
    at Object.Module._extensions..js (module.js:467:10)
    at Module.load (module.js:349:32)
    at Function.Module._load (module.js:305:12)
    at Function.Module.runMain (module.js:490:10)
    at startup (node.js:124:16)
    at node.js:807:3

ignore unknown yielded types

Unfortunately this isn't valid syntax:

var content = id && yield get(id);

so it would be rad if you could write

var content = yield id && get(id);

And if id is falsy it would just be ignored.

proposal: co.convert(obj, include)

Would it be nice to have something like this:

co.convert = function(obj, include) {
  (include || Object.keys(obj)).forEach(function(key) {
    if (obj.hasOwnProperty(key) &&  'function' == typeof obj[key]) {
      obj[key] = co.wrap(obj[key], obj);
    }
  });
};

// wrap all methods on an object
co.convert(myCallbackStyleDBClient);

// wrap specific methods only
co.convert(fs, ['readFile', 'writeFile']);

Instead of having to include wrapper modules all over the place...

errors in README.md

Hi, I found some errors in your demonstration code in README.md file

you said:

var thunkify = require('thunkify');
var request = require('superagent');

var get = thunkify(request.get);

function *results() {
  var a = yield get('http://google.com')
  var b = yield get('http://yahoo.com')
  var c = yield get('http://ign.com')
  return [a.status, b.status, c.status]
}

co(function *(){
  // 3 concurrent requests at a time
  var a = yield results;
  var b = yield results;
  var c = yield results;
  console.log(a, b, c);

  // 9 concurrent requests
  console.log(yield [results, results, results]);
})()

but when I run this test, I found that when running this:

var a = yield results;
  var b = yield results;
  var c = yield results;
  console.log(a, b, c);

instead of 3 concurrent requests at a time, the 9 requests are lined up.

and when running this:

console.log(yield [results, results, results]);

instead of 9 concurrent requests, there are 3 concurrent requests at a time

your comments will cause misunderstanding for people. but overall your work is awesome, thank you!

nicer join

instead of:

co(function *() {
  var commit = exec('git rev-parse HEAD');
  var commits = exec('git rev-list master | wc -l');
  var res = yield join(commit, commits)
  console.log(res[0], res[1]);
});

maybe:

co(function *() {
  var commit = exec('git rev-parse HEAD');
  var commits = exec('git rev-list master | wc -l');
  yield join(commit, commits);
  console.log(commit.res, commits.res);
});

or with destructuring assignment:

co(function *() {
  var commit = exec('git rev-parse HEAD');
  var commits = exec('git rev-list master | wc -l');
  [commit, commits] = yield join(commit, commits);
  console.log(commit, commits);
});

Handle exceptions

There are not many examples on how exceptions are handled, except when using "thunk".

Co is careful to relay any errors that occur back to the generator, including those within the thunk, or from the thunk's callback. "Uncaught" exceptions in the generator are passed to co()'s thunk.

I mean, what does that mean anyway?

It seems like Co is not returning anything... ever. For example :

co(function * (ctx) {
   yield _doSomethingPotentiallyDangerous(ctx);
   yield _doSomeOtherDangerousStuff(ctx);
})(this);   // <--- always undefined
// ^- never any exception thrown even if the two enclosed functions
//    do throw something.

Since, as I understand it, Co is being executed and returns in the same control flow as it consumes the generators internally (?), then any exception should go somewhere and not just swallowed in a void, no?

Some explanation and solution would be appreciated!

“Check for plain object” may be have a problem

function isObject(val) {
  return val && Object == val.constructor;
}

how about:

function isObject(val) {
  return val && 'Object' == val.constructor.name;
}

or like in browser:

function isObject(val) {
  return val && Object.prototype.toString.call(val) === '[object Object]';
}

Catching errors

I'm quite in love with generators but I have a question regarding catching errors. I have a function (query in this case) which throws an error. Now I want to catch it but co should not handle it. The idea behind this is that the program will continue depending on what error raised.

co(function*() {

  var client = yield cypher.createClient("http://localhost:7474");

  var err;
  try {
    // This will throw an error
    yield client.query("DOOMED");
  } catch(e) {
    err = e;
  }

  // Normaly here would be some conditions and so on
  console.log(err.name);

})();

The current output is:

D:\Programme\Node\co-cypher\index.js:16
      if(err) throw err;
                    ^
SyntaxException: Invalid input 'O': expected 'r/R' or 'e/E' (line 1, column 2)
"DOOMED" [and so on; internals of neo4j; not relevant]

And how can I catch the error?

feature request: return the last non-thunkable value in a generator

so we can do something like this:

function* () {
  var obj = {};
  yield async1(obj);
  yield async2(obj);
  yield obj;
}

this way, we can just pass around generators without var co = require('co') and composing them into a thunk every time.

of course, the return value has to be very limited (non-thunkables, can not be an array). ideally, i'd like to allow just objects and buffers.

Just a question: Why do I hang at the end?

Sorry for a newbie to this whole generator, thunkify thing but I have a simple question. I'm fully aware that this probably is just me...

When I run (node --harmony demo.js) a simple like this:

var co = require('co');
var thunkify = require('thunkify');
var request = require('request');
var get = thunkify(request.get);

co(function *(){
  var a = yield get('http://google.com');
  var b = yield get('http://yahoo.com');
  var c = yield get('http://cloudup.com');
  console.log(a[0].statusCode);
  console.log(b[0].statusCode);
  console.log(c[0].statusCode);
})()

This works but, why do I "hang" in the console at the end?
Shouldn't node complete after the last line?

There's something here I don't understand, I believe. Please help me get this.

Wrap all the native/builtin modules?

I saw co-fs and co-exec and I was thinking: Perhaps it would be a good idea to wrap all the native/builtin modules, and have them required like:

var fs = require('co/fs')
var child_process = require('co/child_process')
var crypto = require('co/crypto')
// ...

What do you think?

How are you going to support the browser?

The README says "coming soon to the browser." Just curious what this means. Does it mean it'll work once browsers support generators? Or are you going to do some sort of Google Traceur type magic to support current browsers?

Object key order not maintained across a yield.

Encountered this in koa but suspect it's a co issue. Simplified code:

function*(){
  var results = yield {
    sun: fetch('sun'),
    moon: fetch('moon'),
    sky: fetch('sky')
  };
  Object.keys(results); // moon, sky, sun
}

Perhaps order of responses is dictating returned order? Seems like I remember JS makes no guarantee of object key ordering, but people are in the habit of relying on it (myself included apparently).

return array for multiple arguments

right now if you have a callback signature of (err, foo, bar) yield stuff; will return foo but not bar, so maybe we should check arity and return [foo, bar]

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.