Comparing version 1.3.0 to 1.4.0
1.4.0 / 2013-06-21 | ||
================== | ||
* add promise support to joins | ||
* add `yield generatorFunction` support | ||
* add `yield generator` support | ||
* add nested join support | ||
1.3.0 / 2013-06-10 | ||
@@ -3,0 +11,0 @@ ================== |
99
index.js
/** | ||
* toString reference. | ||
*/ | ||
var toString = Object.prototype.toString; | ||
/** | ||
* Expose `co`. | ||
@@ -18,3 +24,3 @@ */ | ||
var args = [].slice.call(arguments, 1); | ||
var gen = fn.apply(this, args); | ||
var gen = isGenerator(fn) ? fn : fn.apply(this, args); | ||
var done; | ||
@@ -56,8 +62,6 @@ | ||
// array (join) | ||
if (Array.isArray(ret.value)) { | ||
ret.value = exports.join(ret.value); | ||
} | ||
// normalize | ||
ret.value = toThunk(ret.value); | ||
// thunk | ||
// run | ||
if ('function' == typeof ret.value) { | ||
@@ -74,13 +78,4 @@ try { | ||
// promise | ||
if (ret.value && 'function' == typeof ret.value.then) { | ||
ret.value.then(function(value) { | ||
next(null, value); | ||
}, next); | ||
return; | ||
} | ||
// neither | ||
next(new Error('yield a function or promise')); | ||
// invalid | ||
next(new Error('yield a function, promise, generator, or array')); | ||
} | ||
@@ -143,2 +138,4 @@ | ||
try { | ||
fn = toThunk(fn); | ||
fn(function(err, res){ | ||
@@ -162,1 +159,69 @@ if (finished) return; | ||
}; | ||
/** | ||
* Convert `obj` into a normalized thunk. | ||
* | ||
* @param {Mixed} obj | ||
* @return {Function} | ||
* @api private | ||
*/ | ||
function toThunk(obj) { | ||
if (Array.isArray(obj)) obj = exports.join(obj); | ||
if (isGeneratorFunction(obj)) obj = obj(); | ||
if (isGenerator(obj)) obj = co(obj); | ||
if (isPromise(obj)) obj = promiseToThunk(obj); | ||
return obj; | ||
} | ||
/** | ||
* Convert `promise` to a thunk. | ||
* | ||
* @param {Object} promise | ||
* @return {Function} | ||
* @api private | ||
*/ | ||
function promiseToThunk(promise) { | ||
return function(fn){ | ||
promise.then(function(res) { | ||
fn(null, res); | ||
}, fn); | ||
} | ||
} | ||
/** | ||
* Check if `obj` is a promise. | ||
* | ||
* @param {Object} obj | ||
* @return {Boolean} | ||
* @api private | ||
*/ | ||
function isPromise(obj) { | ||
return obj && 'function' == typeof obj.then; | ||
} | ||
/** | ||
* Check if `fn` is a generator. | ||
* | ||
* @param {Mixed} obj | ||
* @return {Boolean} | ||
* @api private | ||
*/ | ||
function isGenerator(obj) { | ||
return obj && '[object Generator]' == toString.call(obj); | ||
} | ||
/** | ||
* Check if `fn` is a generator function. | ||
* | ||
* @param {Mixed} obj | ||
* @return {Boolean} | ||
* @api private | ||
*/ | ||
function isGeneratorFunction(obj) { | ||
return obj && obj.constructor && 'GeneratorFunction' == obj.constructor.name; | ||
} |
{ | ||
"name": "co", | ||
"version": "1.3.0", | ||
"version": "1.4.0", | ||
"description": "generator async flow control goodness", | ||
@@ -5,0 +5,0 @@ "keywords": ["async", "flow", "generator", "coro", "coroutine"], |
110
Readme.md
@@ -14,2 +14,4 @@ # Co | ||
Make sure to view the [examples](https://github.com/visionmedia/co/tree/master/examples). | ||
## Installation | ||
@@ -39,4 +41,22 @@ | ||
}) | ||
co(function *(){ | ||
var a = get('http://google.com'); | ||
var b = get('http://yahoo.com'); | ||
var c = get('http://cloudup.com'); | ||
var res = yield [a, b, c]; | ||
console.log(res); | ||
}) | ||
``` | ||
## Yieldables | ||
The "yieldable" objects currently supported are: | ||
- promises | ||
- thunks (functions) | ||
- array (parallel execution) | ||
- generators (delegation) | ||
- generator functions (delegation) | ||
## Thunks vs promises | ||
@@ -105,5 +125,4 @@ | ||
#### Nesting co() calls | ||
You may also yield `Generator` objects to support nesting: | ||
The `co()` function itself returns a thunk, this means you can nest appropriately: | ||
@@ -123,3 +142,3 @@ ```js | ||
var foo = co(function *(){ | ||
function *foo(){ | ||
var a = yield size('.gitignore'); | ||
@@ -129,5 +148,5 @@ var b = yield size('Makefile'); | ||
return [a, b, c]; | ||
}) | ||
} | ||
var bar = co(function *(){ | ||
function *bar(){ | ||
var a = yield size('examples/parallel.js'); | ||
@@ -137,7 +156,7 @@ var b = yield size('examples/nested.js'); | ||
return [a, b, c]; | ||
}) | ||
} | ||
co(function *(){ | ||
var a = yield foo; | ||
var b = yield bar; | ||
var a = yield foo(); | ||
var b = yield bar(); | ||
console.log(a); | ||
@@ -148,34 +167,25 @@ console.log(b); | ||
Or a variation of the same thing: | ||
Or if the generator functions do not require arguments, simply `yield` the function: | ||
```js | ||
var co = require('co'); | ||
var fs = require('fs'); | ||
var request = require('superagent'); | ||
function size(file) { | ||
return function(fn){ | ||
fs.stat(file, function(err, stat){ | ||
if (err) return fn(err); | ||
fn(null, stat.size); | ||
}); | ||
} | ||
var get = co.wrap(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 *(){ | ||
var a = yield co(function *(){ | ||
var a = yield size('.gitignore'); | ||
var b = yield size('Makefile'); | ||
var c = yield size('package.json'); | ||
return [a, b, c]; | ||
}) | ||
// 3 concurrent requests at a time | ||
var a = yield results; | ||
var b = yield results; | ||
var c = yield results; | ||
console.log(a, b, c); | ||
var b = yield co(function *(){ | ||
var a = yield size('examples/parallel.js'); | ||
var b = yield size('examples/nested.js'); | ||
var c = yield size('examples/simple.js'); | ||
return [a, b, c]; | ||
}) | ||
console.log(a); | ||
console.log(b); | ||
// 9 concurrent requests | ||
console.log(yield [results, results, results]); | ||
}); | ||
@@ -297,28 +307,18 @@ ``` | ||
## FAQ | ||
Nested joins may also be expressed as simple nested arrays: | ||
### How does this compare to taskjs? | ||
- it's smaller | ||
- it's not a scheduler | ||
- you can use thunks (functions) | ||
- you can use promises | ||
### Does it work with streams? | ||
Not out of the box, but if you're willing to fight node a bit you can | ||
wrestle streams into something usable: | ||
```js | ||
co(function *(){ | ||
var res = yield get('http://google.com'); | ||
console.log('-> %s', res.status); | ||
var a = [ | ||
get('http://google.com'), | ||
get('http://yahoo.com'), | ||
get('http://ign.com') | ||
]; | ||
var buf; | ||
while (buf = yield res.read()) { | ||
console.log(buf.toString()); | ||
} | ||
var b = [ | ||
get('http://google.com'), | ||
get('http://yahoo.com'), | ||
get('http://ign.com') | ||
]; | ||
console.log('done'); | ||
}) | ||
console.log(yield [a, b]); | ||
``` | ||
@@ -325,0 +325,0 @@ |
@@ -218,3 +218,3 @@ | ||
var msg = 'yield a function or promise'; | ||
var msg = 'yield a function, promise, generator, or array'; | ||
errors.should.eql([msg, msg]); | ||
@@ -221,0 +221,0 @@ done(); |
29839
22
852