run-callback
Advanced tools
Comparing version
81
index.js
@@ -0,5 +1,80 @@ | ||
var eos = require('end-of-stream') | ||
var consume = require('stream-consume') | ||
exports = module.exports = require('./lib/run') | ||
exports.bind = exports.bindAsync = require('./lib/bindAsync') | ||
exports.chain = require('./lib/chain') | ||
exports = module.exports = function (cb) { | ||
return thunkify(cb).apply(null, slice(arguments, 1)) | ||
} | ||
exports.thunkify = thunkify | ||
function thunkify(fn, ctx) { | ||
if (typeof fn === 'string') { | ||
fn = ctx[fn] | ||
} | ||
return function () { | ||
var args = slice(arguments) | ||
// For async callbacks, | ||
// the number of arguments provided should be at least one less than declared. | ||
var maybeAsync = fn.length > args.length | ||
return new Promise(function (resolve, reject) { | ||
function done(err) { | ||
if (err) { | ||
return reject(err) | ||
} | ||
resolve(normalizeResult(slice(arguments, 1))) | ||
} | ||
var r = fn.apply(ctx, maybeAsync ? args.concat(done) : args) | ||
if (isPromise(r)) { | ||
r.then(done.bind(null, null), done) | ||
return | ||
} | ||
if (isStream(r)) { | ||
eos(r, { | ||
error: true, | ||
readable: r.readable, | ||
writable: r.writable && !r.readable, | ||
}, function (err) { | ||
done(err) | ||
}) | ||
consume(r) | ||
return | ||
} | ||
if (!maybeAsync) { | ||
done(null, r) | ||
} | ||
}) | ||
} | ||
} | ||
function isPromise(o) { | ||
return o && typeof o.then === 'function' | ||
} | ||
function isStream(s) { | ||
return s && typeof s.pipe === 'function' | ||
} | ||
function slice(o, from, to) { | ||
return Array.prototype.slice.call(o, from, to) | ||
} | ||
function normalizeResult(res) { | ||
var top | ||
while (res.length) { | ||
top = res.pop() | ||
if (typeof top !== 'undefined') { | ||
res.push(top) | ||
break | ||
} | ||
} | ||
return res | ||
} | ||
{ | ||
"name": "run-callback", | ||
"version": "2.2.0", | ||
"version": "3.0.0", | ||
"description": "Run async & sync callbacks", | ||
@@ -10,8 +10,5 @@ "main": "index.js", | ||
"scripts": { | ||
"test": "npm run lint && task-tape test/*.js | tap-summary", | ||
"lint": "eslint *.js lib/**/*.js test/*.js bin/*.js", | ||
"coverage": "istanbul cover -i 'lib/**/*.js' -i '*.js' --print both task-tape -- test/*.js", | ||
"check-coverage": "istanbul check-coverage --statements 90 --functions 90 --branches 85 --lines 90", | ||
"upload-coverage": "cat ./coverage/lcov.info | coveralls", | ||
"cover": "npm run coverage && npm run check-coverage && npm run upload-coverage" | ||
"test": "npm run lint && tap --cov test/*.js", | ||
"lint": "eslint *.js 'lib/**/*.js' test/*.js bin/*.js", | ||
"coveralls": "COVERALLS_REPO_TOKEN=ppZU3BC1fUw5uE4CklIcIWNbNkB3D8SxZ npm test" | ||
}, | ||
@@ -34,13 +31,8 @@ "repository": { | ||
"end-of-stream": "^1.1.0", | ||
"once": "^1.3.2", | ||
"stream-consume": "^0.1.0" | ||
}, | ||
"devDependencies": { | ||
"coveralls": "^2.11.4", | ||
"eslint": "^1.4.3", | ||
"istanbul": "^0.4.0", | ||
"tap-summary": "^1.0.0", | ||
"tape": "^4.2.0", | ||
"task-tape": "^1.2.2" | ||
"tap": "^2.3.1" | ||
} | ||
} |
236
README.md
# run-callback | ||
Run async or sync callbacks, such as [gulp tasks](https://github.com/gulpjs/gulp/blob/master/docs/API.md#fn). | ||
[](https://www.npmjs.org/package/run-callback) | ||
[](https://www.npmjs.org/package/run-callback) | ||
@@ -14,206 +12,102 @@ [](https://travis-ci.org/zoubin/run-callback) | ||
# Usage | ||
## Usage | ||
## run(callback, done) | ||
Run `callback`, and call `done` when it finishes | ||
### callback | ||
Type: `Function`, `Array` | ||
`callback` can be made asynchronous if it does one of the following: | ||
#### Return a promise | ||
```javascript | ||
var run = require('run-callback') | ||
var thunkify = run.thunkify | ||
run( | ||
[function (a, b) { | ||
return new Promise(function (rs) { | ||
rs(a + b) | ||
}) | ||
}, | ||
2, 1], | ||
function (err, sum) { | ||
console.log('Expected:', 3) | ||
console.log('Actual:', sum) | ||
} | ||
) | ||
``` | ||
#### Return a stream | ||
### promise = run(callback, ...args) | ||
```javascript | ||
var run = require('run-callback') | ||
var Stream = require('stream') | ||
Run `callback` with `args`, | ||
and return a promise to fetch the results, | ||
which is always an `Array`. | ||
var res = [] | ||
run( | ||
[function (a, b) { | ||
var rs = Stream.Readable({ objectMode: true }) | ||
var data = [a, b] | ||
rs._read = function () { | ||
if (data.length) { | ||
this.push(data.pop()) | ||
} else { | ||
this.push(null) | ||
} | ||
} | ||
process.nextTick(function () { | ||
rs.on('data', function (d) { | ||
res.push(d) | ||
}) | ||
}) | ||
return rs | ||
}, 1, 2], | ||
function () { | ||
console.log('Expected:', [2, 1]) | ||
console.log('Actual:', res) | ||
} | ||
) | ||
#### callback | ||
``` | ||
Type: `Function` | ||
#### Accept one more argument than given | ||
`callback` can be made asynchronous if it does one of the following: | ||
That extra argument should be a function. | ||
##### Return a promise | ||
```javascript | ||
var run = require('run-callback') | ||
run( | ||
[function (a, b, done) { | ||
run(function () { | ||
return new Promise(function (resolve) { | ||
process.nextTick(function () { | ||
done(null, a + b, a - b) | ||
resolve('done') | ||
}) | ||
}, | ||
2, 1], | ||
function (err, sum, diff) { | ||
console.log('Expected:', 3, 1) | ||
console.log('Actual:', sum, diff) | ||
} | ||
) | ||
}) | ||
}) | ||
.then(function (res) { | ||
// 'done' | ||
console.log(res[0]) | ||
}) | ||
``` | ||
### done | ||
##### Return a stream | ||
Type: `Function` | ||
```javascript | ||
var Readable = require('stream').Readable | ||
Signature: `done(err, val1, val2,...)` | ||
var src = ['beep', '\n', 'boop'] | ||
run(function () { | ||
var stream = createStream(src) | ||
stream.pipe(process.stdout) | ||
return stream | ||
}) | ||
.then(function () { | ||
console.log('\n') | ||
// `[]` | ||
console.log(src) | ||
}) | ||
#### Synchronous | ||
`done` will be called when `callback` finishes. | ||
Errors thrown when executing `callback` will be passed to `done` as the first argument, | ||
and the returned value as the second. | ||
```javascript | ||
var run = require('run-callback') | ||
run( | ||
[function (a, b, done) { | ||
process.nextTick(function () { | ||
done(null, a + b, a - b) | ||
}) | ||
}, | ||
2, 1], | ||
function (err, sum, diff) { | ||
console.log('Expected:', 3, 1) | ||
console.log('Actual:', sum, diff) | ||
function createStream(source) { | ||
var rs = Readable() | ||
rs._read = function () { | ||
if (source.length) { | ||
this.push(source.pop()) | ||
} else { | ||
this.push(null) | ||
} | ||
} | ||
) | ||
return rs | ||
} | ||
``` | ||
#### Promisified | ||
`done` will be called when the returned promise resolves. | ||
##### Accept one more argument than declared | ||
Any rejected values will be passed as the first arugment, | ||
and any fulfilled values as the second. | ||
```javascript | ||
run(function (a, b, next) { | ||
process.nextTick(function () { | ||
next(null, a + b, a - b) | ||
}) | ||
}, 2, 1) | ||
.then(function (res) { | ||
// `[3, 1]` | ||
console.log(res) | ||
}) | ||
#### Streamified | ||
`done` will be called when the returned stream ends (readable, transforms, duplex) or finishes (writable). | ||
``` | ||
Errors will be passed as the first arugment. | ||
### run.thunkify(fn, context) | ||
#### Other | ||
Return a new function to run `fn` later with a list of arguments. | ||
`done` will be called when `callback` invokes the last argument (`next`) with a possible error object and more values. | ||
`done` will be called with the same arguments with `next`. | ||
## run.bind([ctx,]callback, arg1, arg2,...) | ||
## run.bindAsync([ctx,]callback, arg1, arg2,...) | ||
### ctx | ||
Type: `Object` | ||
If specified, it will be used as the execution context of `callback`. | ||
### callback | ||
Type: `Function`, `String` | ||
If `String`, it should be a method name of `ctx`, | ||
and that method will be treated as the `callback`. | ||
### args | ||
The arguments following `callback` will be passed as arguments to `callback` when it is executed. | ||
## run.chain(callbacks, done) | ||
Chain [callback](#callback)s together. | ||
Values returned from the previous callback | ||
will be appended to the argument list of the next. | ||
### callbacks | ||
Type: `Array` | ||
### done | ||
Type: `Function` | ||
Signature: `done(err,...args)` | ||
```javascript | ||
var chain = require('run-callback').chain | ||
var task = run.thunkify(function (a, b, next) { | ||
process.nextTick(function () { | ||
next(null, a + b, a - b) | ||
}) | ||
}) | ||
chain([ | ||
[function (v, cb) { | ||
// 1 | ||
console.log(v) | ||
process.nextTick(function () { | ||
cb(null, 1, 2) | ||
}) | ||
}, 1], | ||
[function (a, b, c) { | ||
// [3, 1, 2] | ||
console.log([a, b, c]) | ||
return Promise.resolve([b, c]) | ||
}, 3], | ||
function (a) { | ||
// [1, 2] | ||
console.log(a) | ||
return [1, 2] | ||
}, | ||
function (a, cb) { | ||
// [1, 2] | ||
console.log(a) | ||
cb(null, 1, 2) | ||
}, | ||
], function (err, a, b) { | ||
// [1, 2] | ||
console.log([a, b]) | ||
task(2, 1).then(function (res) { | ||
// `[3, 1]` | ||
console.log(res) | ||
}) | ||
``` | ||
2
-33.33%2
-66.67%6411
-21.65%4
-33.33%64
-33.33%113
-48.4%- Removed