3 function isPromise(obj) {
4 return !!obj && (typeof obj === 'object' || typeof obj === 'function') && typeof obj.then === 'function';
8 * Return a function that will run a function asynchronously or synchronously
11 * runAsync(wrappedFunction, callback)(...args);
13 * @param {Function} func Function to run
14 * @param {Function} cb Callback function passed the `func` returned value
15 * @return {Function(arguments)} Arguments to pass to `func`. This function will in turn
16 * return a Promise (Node >= 0.12) or call the callbacks.
19 var runAsync = module.exports = function (func, cb) {
20 cb = cb || function () {};
26 var promise = new Promise(function (resolve, reject) {
28 const wrappedResolve = function (value) {
30 console.warn('Run-async promise already resolved.')
37 const wrappedReject = function (value) {
39 console.warn('Run-async promise already rejected.')
45 var usingCallback = false;
46 var callbackConflict = false;
47 var contextEnded = false;
49 var answer = func.apply({
52 console.warn('Run-async async() called outside a valid run-async context, callback will be ignored.');
55 if (callbackConflict) {
56 console.warn('Run-async wrapped function (async) returned a promise.\nCalls to async() callback can have unexpected results.');
59 return function (err, value) {
63 wrappedResolve(value);
67 }, Array.prototype.slice.call(args));
70 if (isPromise(answer)) {
71 console.warn('Run-async wrapped function (sync) returned a promise but async() callback must be executed to resolve.');
74 if (isPromise(answer)) {
75 callbackConflict = true;
76 answer.then(wrappedResolve, wrappedReject);
78 wrappedResolve(answer);
84 promise.then(cb.bind(null, null), cb);
90 runAsync.cb = function (func, cb) {
91 return runAsync(function () {
92 var args = Array.prototype.slice.call(arguments);
93 if (args.length === func.length - 1) {
94 args.push(this.async());
96 return func.apply(this, args);