Comparing version 0.0.1 to 1.0.0
25
index.js
@@ -0,1 +1,8 @@ | ||
var isGenerator = function (val) { | ||
return val && typeof val.next === 'function' && typeof val.throw === 'function' | ||
} | ||
var isPromise = function (val) { | ||
return val && typeof val.then === 'function' | ||
} | ||
module.exports = function caco (gen) { | ||
@@ -8,9 +15,5 @@ return function () { | ||
args.push(function next (err, res) { | ||
process.nextTick(function () { | ||
step(err, res) | ||
}) | ||
}) | ||
args.push(next) | ||
var iter = gen.apply(self, args) | ||
var iter = isGenerator(gen) ? gen : gen.apply(self, args) | ||
@@ -24,3 +27,3 @@ function step (err, res) { | ||
if (state.value && typeof state.value.then === 'function') { | ||
if (isPromise(state.value)) { | ||
// handle thenable | ||
@@ -32,2 +35,4 @@ state.value.then(function (value) { | ||
}) | ||
} else if (isGenerator(state.value)) { | ||
caco(state.value)(next) | ||
} else if (state.done) { | ||
@@ -42,2 +47,8 @@ step(null, state.value) | ||
function next (err, res) { | ||
process.nextTick(function () { | ||
step(err, res) | ||
}) | ||
} | ||
if (callback) { | ||
@@ -44,0 +55,0 @@ step() |
{ | ||
"name": "caco", | ||
"version": "0.0.1", | ||
"description": "Async generator control flow that supports both callback and promise", | ||
"version": "1.0.0", | ||
"description": "Generator based control flow that supports both callbacks and promises", | ||
"scripts": { | ||
@@ -6,0 +6,0 @@ "test": "standard && node test.js" |
@@ -1,33 +0,39 @@ | ||
# sema | ||
# caco | ||
Async semaphore for shared or exclusive execution of JavaScript functions. | ||
Generator based control flow that supports both callbacks and promises. | ||
[![Build Status](https://travis-ci.org/cshum/sema.svg?branch=master)](https://travis-ci.org/cshum/sema) | ||
[![Build Status](https://travis-ci.org/cshum/caco.svg?branch=master)](https://travis-ci.org/cshum/caco) | ||
Many of the existing async libraries require wrapping callback functions into promises to be usuable, which creates unnecessary complication. | ||
In caco, both callbacks and promises are 'yieldable'; | ||
resulting function can be used by both callbacks and promises. | ||
This enables a powerful control flow while maintaining compatibility. | ||
```bash | ||
npm install caco | ||
``` | ||
npm install sema | ||
``` | ||
```js | ||
var sema = require('sema') | ||
var s = sema() | ||
var caco = require('caco') | ||
// exclusive mode | ||
s.acquire(function () { | ||
... | ||
doReadWrite(function (err) { | ||
... | ||
s.release() | ||
}) | ||
}) | ||
var fn = caco(function * (next) { | ||
var foo = yield Promise.resolve('bar') // yield promise | ||
yield setTimeout(next, 100) // yield callback using 'next' argument | ||
// shared mode | ||
s.acquire(sema.SHARED, function () { | ||
... | ||
doReadOnly(function (err) { | ||
... | ||
s.release() | ||
}) | ||
// try/catch errors | ||
try { | ||
yield Promise.reject('boom') | ||
} catch (err) { | ||
console.log(err) // 'boom' | ||
} | ||
var data = yield fs.readFile('./foo/bar', next) | ||
return data | ||
}) | ||
// consume with callback | ||
fn(function (err, res) { }) | ||
fn().then(...).catch(...) | ||
``` | ||
@@ -37,30 +43,26 @@ | ||
### var s = sema() | ||
Creates a semaphore instance. | ||
#### var fn = caco(fn *) | ||
### s.acquire([mode], [fn]) | ||
Acquire semaphore. Defaults to exclusive mode. Setting mode `sema.SHARED` to acquire a shared mode. | ||
Wraps a generator into a regular function that acceots callback or promise. | ||
Callback to asynchronous function `fn` when semaphore available. | ||
Invoked immediately if semaphore is free or shared only. Otherwise pushed to the wait queue. | ||
```js | ||
var getN = caco(function * (n, next) { | ||
if (n === 689) yield Promise.reject('boom') // yield reject throws error | ||
return yield Promise.resolve(n) | ||
}) | ||
Returns a promise if no `fn` provided. However this yields a slight delay when acquiring, due to the nature of promise. If such timing is important then callback function should be used. | ||
getN(123, function (err, val) { | ||
console.log(val) // 123 | ||
}) | ||
getN(123).then(...) | ||
### s.release() | ||
Release semaphore. | ||
getN(689).catch(function (err) { | ||
console.log(err) // boom | ||
}) | ||
``` | ||
Invokes function from the wait queue if queue is not empty. | ||
Generator accepts optional `next` argument for yieldable callback | ||
### s.mode() | ||
## License | ||
Returns mode constant, the current state of semaphore. | ||
### Mode Constants | ||
* **`sema.FREE = null`** | ||
* **`sema.SHARED = 1`** | ||
* **`sema.EXCLUSIVE = 2`** | ||
* **`sema.WAIT = 3`** | ||
## License | ||
MIT |
24
test.js
@@ -5,5 +5,9 @@ var test = require('tape') | ||
test('caco', function (t) { | ||
t.plan(3) | ||
var v = caco(function * () { | ||
return 167 | ||
t.plan(5) | ||
function * v (n) { | ||
return yield Promise.resolve(n) | ||
} | ||
var n = caco(function * (n) { | ||
return yield Promise.reject(n) | ||
}) | ||
@@ -15,3 +19,7 @@ var v1 = caco(function * (next) { | ||
var v2 = caco(function * () { | ||
return yield v() | ||
try { | ||
return yield n(689) | ||
} catch (e) { | ||
return yield v(167) | ||
} | ||
}) | ||
@@ -23,2 +31,10 @@ var f = caco(function * (str, next) { | ||
n('boom', function (err) { | ||
t.equal(err, 'boom', 'correct callback error') | ||
}) | ||
n('boom').then(t.error).catch(function (err) { | ||
t.equal(err, 'boom', 'correct promise reject') | ||
}) | ||
f('D7', function (err, res) { | ||
@@ -25,0 +41,0 @@ t.notOk(err, 'no error') |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
5764
95
1
68