126 lines
2.1 KiB
JavaScript
126 lines
2.1 KiB
JavaScript
|
/**
|
||
|
* Module Dependencies
|
||
|
*/
|
||
|
|
||
|
var noop = function(){};
|
||
|
var co = require('co');
|
||
|
|
||
|
/**
|
||
|
* Export `wrap-fn`
|
||
|
*/
|
||
|
|
||
|
module.exports = wrap;
|
||
|
|
||
|
/**
|
||
|
* Wrap a function to support
|
||
|
* sync, async, and gen functions.
|
||
|
*
|
||
|
* @param {Function} fn
|
||
|
* @param {Function} done
|
||
|
* @return {Function}
|
||
|
* @api public
|
||
|
*/
|
||
|
|
||
|
function wrap(fn, done) {
|
||
|
done = once(done || noop);
|
||
|
|
||
|
return function() {
|
||
|
// prevents arguments leakage
|
||
|
// see https://github.com/petkaantonov/bluebird/wiki/Optimization-killers#3-managing-arguments
|
||
|
var i = arguments.length;
|
||
|
var args = new Array(i);
|
||
|
while (i--) args[i] = arguments[i];
|
||
|
|
||
|
var ctx = this;
|
||
|
|
||
|
// done
|
||
|
if (!fn) {
|
||
|
return done.apply(ctx, [null].concat(args));
|
||
|
}
|
||
|
|
||
|
// async
|
||
|
if (fn.length > args.length) {
|
||
|
// NOTE: this only handles uncaught synchronous errors
|
||
|
try {
|
||
|
return fn.apply(ctx, args.concat(done));
|
||
|
} catch (e) {
|
||
|
return done(e);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// generator
|
||
|
if (generator(fn)) {
|
||
|
return co(fn).apply(ctx, args.concat(done));
|
||
|
}
|
||
|
|
||
|
// sync
|
||
|
return sync(fn, done).apply(ctx, args);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Wrap a synchronous function execution.
|
||
|
*
|
||
|
* @param {Function} fn
|
||
|
* @param {Function} done
|
||
|
* @return {Function}
|
||
|
* @api private
|
||
|
*/
|
||
|
|
||
|
function sync(fn, done) {
|
||
|
return function () {
|
||
|
var ret;
|
||
|
|
||
|
try {
|
||
|
ret = fn.apply(this, arguments);
|
||
|
} catch (err) {
|
||
|
return done(err);
|
||
|
}
|
||
|
|
||
|
if (promise(ret)) {
|
||
|
ret.then(function (value) { done(null, value); }, done);
|
||
|
} else {
|
||
|
ret instanceof Error ? done(ret) : done(null, ret);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Is `value` a generator?
|
||
|
*
|
||
|
* @param {Mixed} value
|
||
|
* @return {Boolean}
|
||
|
* @api private
|
||
|
*/
|
||
|
|
||
|
function generator(value) {
|
||
|
return value
|
||
|
&& value.constructor
|
||
|
&& 'GeneratorFunction' == value.constructor.name;
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Is `value` a promise?
|
||
|
*
|
||
|
* @param {Mixed} value
|
||
|
* @return {Boolean}
|
||
|
* @api private
|
||
|
*/
|
||
|
|
||
|
function promise(value) {
|
||
|
return value && 'function' == typeof value.then;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Once
|
||
|
*/
|
||
|
|
||
|
function once(fn) {
|
||
|
return function() {
|
||
|
var ret = fn.apply(this, arguments);
|
||
|
fn = noop;
|
||
|
return ret;
|
||
|
};
|
||
|
}
|