User Rating 0.0
Total Usage 0 times
Input (Callback-style)
Output (Yieldable)
Is this tool helpful?

Your feedback helps us improve.

About

Node.js callback conventions follow the error-first pattern: the last argument is a function receiving err and result. Generator-based control flow libraries such as co expect yieldable values - thunks or Promises. Manually wrapping every callback function is tedious and error-prone. A missed error branch or a swapped argument index causes silent failures that surface only at runtime under load. This tool parses your callback-style function signatures and emits wrapped versions as thunks (single-arity functions returning function(done)) or as Promises via explicit constructor or util.promisify output. It handles arrow functions, rest parameters, and default values. The conversion is purely structural - it does not execute your code. Limitation: deeply nested or dynamically constructed callbacks cannot be detected by static pattern matching.

callback yieldable thunk promise nodejs generator co promisify converter javascript

Formulas

A thunk is a function of arity 1 that accepts a single done callback. The conversion identity for an error-first callback function f with n arguments plus callback:

thunkify(f) = function(a1, a2, …, an) { return function(done) { f(a1, …, an, done); }; }

The Promise conversion follows the constructor pattern:

promisify(f) = function(a1, …, an) { return new Promise(function(resolve, reject) { f(a1, …, an, function(err, res) { if (err) reject(err); else resolve(res); }); }); }

Where f is the original callback-style function, a1 through an are the non-callback arguments, done is the thunk consumer callback, err follows the Node.js error-first convention, and res is the success value. The util.promisify output delegates to Node's internal implementation which additionally respects util.promisify.custom symbols.

Reference Data

PatternSignatureYieldable?Output Styleco Compatibleasync/await Compatible
Error-first callbackfn(arg, cb(err, res))No (raw)Thunk / PromiseAfter wrapAfter wrap
Thunkfn(arg) → function(done)YesNativeYesNo
Promisefn(arg) → PromiseYesNativeYesYes
util.promisifyutil.promisify(fn)YesPromiseYesYes
Node streamEventEmitter-basedNoNeeds wrapper libNoNo
Synchronousfn(arg) → valueYes (trivially)Already yieldableYesYes
Multi-callbackfn(onSuccess, onError)NoCustom wrap neededNoNo
Continuation-passingfn(arg, k)NoThunk-convertibleAfter wrapAfter wrap
Bluebird promisifyAllBulk conversionYesPromiseYesYes
cb-style with contextobj.method(arg, cb)NoNeeds .bindAfter bind+wrapAfter bind+wrap
Nested callbacksCallback inside callbackNoFlatten firstNoNo
Event + callback hybridMixed patternsNoManual refactorNoNo

Frequently Asked Questions

A thunk is a function that accepts a single callback argument (function(done){ ... }). Libraries like co detect thunks by checking if the yielded value is a function of arity 1. Promises expose .then() and are also detected by co. The practical difference: thunks are lighter (no microtask queue overhead) but cannot be composed with async/await. Promises integrate with the language natively since ES2017. For new code, Promises are preferred. For legacy co/koa v1 codebases, thunks remain relevant.
The converter identifies the last parameter of each function signature and checks if its name matches common callback conventions: cb, callback, done, next, fn, handler. You can also specify a custom callback parameter name. If the last parameter does not match any convention, the function is flagged as non-convertible unless you force conversion.
In the error-first convention, some functions pass multiple success values: cb(null, result1, result2). The thunk output preserves all arguments as-is since the thunk consumer receives the raw callback arguments. The Promise output resolves with the first result by default. If you enable the "multi-result" option, it resolves with an array [result1, result2, ...]. Node's util.promisify uses a custom symbol [util.promisify.custom] for such cases.
By default, the wrapper calls the original function without explicit binding, inheriting whatever this context the caller provides. If you need to preserve a specific context (e.g., an object method), enable the "Bind Context" option. This wraps the call with .call(this, ...) so the wrapper is transparent to this.
Yes. The parser recognizes arrow function syntax (const fn = (arg, cb) => { ... }), function declarations, function expressions, and module.exports assignments. It also detects exports.methodName patterns. Arrow functions that use implicit return (no braces) with a callback parameter are uncommon and likely indicate a non-callback pattern; the converter will flag these with a warning.
Thunks handle synchronous callbacks correctly since the done function is invoked immediately. Promises always resolve asynchronously due to microtask scheduling. This means code relying on synchronous callback execution order may behave differently after promisification. The converter adds a comment warning when it detects potential synchronous callback invocations.