Skip to content

Commit

Permalink
util: add util.callbackify()
Browse files Browse the repository at this point in the history
Add `util.callbackify(function)` for creating callback style functions
from functions returning a `Promise`/`awaitable`

Fixes: nodejs/CTC#109
  • Loading branch information
refack committed Jun 7, 2017
1 parent 8d2bd5f commit d9a1715
Showing 1 changed file with 55 additions and 0 deletions.
55 changes: 55 additions & 0 deletions lib/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -1045,3 +1045,58 @@ process.versions[exports.inspect.custom] =
(depth) => exports.format(JSON.parse(JSON.stringify(process.versions)));

exports.promisify = internalUtil.promisify;

// Callbackify section
const CBFY_ERR = 'The last argument to the callbackified function must be a ' +
'callback style function';


function callbackifyOnRejected(reason, cb) {
// !reason guard inspired by BlueBird https://goo.gl/t5IS6M
// Because `null` is a special error value in callbacks which means "no error
// occurred". We error-wrap so the callback consumer can distinguish between
// "the promise rejected with null" or "the promise fulfilled with undefined".
if (!reason) {
const newRej = new Error(reason + '');
newRej.cause = reason;
reason = newRej;
}
return cb(reason);
}


function assertLastArgIsFunction(args) {
const cb = args.pop();
if (typeof cb !== 'function') throw new TypeError(CBFY_ERR);
return cb;
}


/**
* @function callbackify
* @param {function(): Promise} asyncEndpoint
* @public
*/
function callbackify(asyncEndpoint) {
if (typeof asyncEndpoint !== 'function')
throw new TypeError('The argument to callbackify() must be a function');

// We DO NOT return the promise as it gives the user a false sense that
// the promise is actually somehow related to the callback's execution
// and that the callback throwing will reject the promise.
function callbackified(...args) {
const cb = assertLastArgIsFunction(args);
asyncEndpoint.call(this, ...args)
.then((ret) => process.nextTick(cb, null, ret),
(rej) => process.nextTick(callbackifyOnRejected, rej, cb)
);
}

Object.setPrototypeOf(callbackified, Object.getPrototypeOf(asyncEndpoint));
Object.defineProperties(callbackified,
Object.getOwnPropertyDescriptors(asyncEndpoint));
return callbackified;
}

exports.callbackify = callbackify;
// End Callbackify

0 comments on commit d9a1715

Please sign in to comment.