raco
Generator based flow-control that supports both callback and promise.
npm install raco
Many existing flow-control libraries such as co, assume promises to be the lowest denominator of async handling.
Callback function requires promisify patch to be compatible,
which creates unnecessary complication.
In raco, both callbacks and promises are yieldable.
Resulting function can be called by both callbacks and promises.
This enables a powerful control flow while maintaining simplicity.
raco(fn*, [opts])
Resolves a generator function.
This does not return a Promise; uncaught error will be thrown.
var raco = require('raco')
...
raco(function * (next) {
console.log(yield Promise.resolve('foo'))
try {
yield Promise.reject(new Error('boom'))
} catch (err) {
console.log(err.message)
}
yield setTimeout(next, 1000)
var data = yield fs.readFile('./data', next)
yield mkdirp('/tmp/foo/bar', next)
yield pump(
fs.createReadStream('./foo'),
fs.createWriteStream('./bar'),
next
)
})
Yieldable callback works by supplying an additional next
argument.
Yielding non-yieldable value pauses the current generator,
until next(err, val)
being invoked by callback.
val
passes back to yielded value, or throw
if err
exists.
raco(function * (next) {
var res = yield setTimeout(() => {
next(null, 'foo')
}, 100)
console.log(res)
try {
yield setTimeout(() => {
next(new Error('boom'))
}, 100)
} catch (err) {
console.log(err.message)
}
})
fn = raco.wrap(fn*, [opts])
Wraps a generator function into regular function that optionally accepts callback or returns a promise.
var fn = raco.wrap(function * (arg1, arg2, next) {
...
return arg1 + arg2
})
fn(167, 199, (err, val) => { ... })
fn(167, 689)
.then((val) => { ... })
.catch((err) => { ... })
raco.wrapAll(obj, [opts])
Wraps generator methods of class or object.
class App {
* fn (next) { ... }
* fn2 (next) { ... }
}
raco.wrapAll(App.prototype)
var app = new App()
app.fn((err, val) => {...})
app.fn2().then(...).catch(...)
Options
Calling raco with options object makes a factory function with a set of available options:
var raco = require('raco')({
Promise: null,
yieldable: function (val, cb) {
},
prepend: true
})
opts.Promise
Raco uses native promise by default. This can be overridden by setting raco.Promise
.
var raco = require('raco')({ Promise: require('bluebird') })
opts.prepend
By default, next(err, val)
function appends to arguments fn* (args..., next)
.
If opts.prepend
set to true
, generator function is called with fn* (next, args...)
.
This can be useful for functions that accept varying numbers of arguments.
var raco = require('raco')
var fn = raco.wrap(function * (next, a, b) {
return a + b
}, { prpend: true })
fn(1, 6, (err, val) => {
console.log(val)
})
fn(1, 6).then((val) => {
console.log(val)
})
opts.yieldable
By default, the following objects are considered yieldable:
- Promise
- Generator
- Generator Function
- Thunk
It is also possible to override the default yieldable mapper. Use with caution:
- Takes the yielded value, returns
true
to acknowledge yieldable. - Callback
cb(err, val)
to resolve the yieldable.
var raco = require('raco')({
yieldable: (val, cb) => {
if (Array.isArray(val)) {
Promise.all(val).then((res) => {
cb(null, res)
}, cb)
return true
}
if (val === 689) {
cb(new Error('DLLM'))
return true
}
return false
}
})
raco(function * () {
console.log(yield [
Promise.resolve(1),
Promise.resolve(2),
3
])
try {
yield 689
} catch (err) {
console.log(err.message)
}
})
License
MIT