User Rating 0.0
Total Usage 0 times
Examples:
Callback Function
Promise Equivalent
Is this tool helpful?

Your feedback helps us improve.

About

Node.js adopted the error-first callback convention (err, result) before Promises became native in ES2015. Migrating legacy codebases manually is tedious and error-prone. A misplaced reject or a forgotten this binding silently breaks async chains, producing unhandled rejections that crash production processes. This tool parses your callback-style function signatures and generates correct Promise wrappers, preserving static properties and flagging this references that require explicit context. It follows the same pattern used by Node.js core util.promisify and libraries like promo and bluebird.

Limitations: this tool operates on source text, not a full AST. It handles standard patterns reliably but may require manual adjustment for deeply nested or dynamically constructed callbacks. Functions that call their callback multiple times will only resolve the first invocation.

callback promise promisify javascript nodejs async converter

Formulas

The promisification pattern wraps a callback-accepting function f in a Promise constructor. The core transformation follows this structure:

promisify(f, ctx) function(...args) {
return new Promise((resolve, reject) {
f.call(ctx, ...args, (err, ...results) {
if (err) reject(err)
else resolve(results.length 1 ? results[0] : results)
})
})
}

Where f is the original callback-based function, ctx is the optional this context (defaults to NULL if not provided), args are all arguments except the callback, err follows the Node.js error-first convention (first callback argument), and results captures remaining callback arguments. When results.length 1, the single value is unwrapped from the array.

Static property preservation uses Object.keys(f).forEach(key wrapper[key] = f[key]) to copy all enumerable properties from the original function to the promisified wrapper.

Reference Data

PatternCallback SignaturePromise EquivalentNotes
Error-firstfn(arg, cb(err, res))fn(arg).then(res)Node.js standard
No errorfn(arg, cb(res))fn(arg).then(res)Always resolves
Multi-resultcb(err, a, b)resolve([a, b])Array destructure
Context-boundobj.method(cb)promisify(method, obj)Requires this binding
Static propsfn.syncCopied to wrapperObject.keys enumeration
util.promisifyNode ≥ 8.0Native supportBuilt-in since Node 8
BluebirdPromise.promisifyThird-partyAdds cancellation support
promopromo(fn)Lightweight wrapperUses es6-promise polyfill
pifypify(fn)Sindre SorhusSupports multi-arg
fs.readFilereadFile(path, cb)readFile(path).then()Classic example
fs.writeFilewriteFile(path, data, cb)writeFile(path, data).then()Classic example
globglob(pattern, cb)glob(pattern).then()Has .sync property
mkdirpmkdirp(dir, cb)mkdirp(dir).then()Recursive mkdir
setTimeoutsetTimeout(cb, ms)Custom wrapper neededNon-standard signature
EventEmitteron(event, cb)Not directly promisifiableMulti-fire pattern

Frequently Asked Questions

A Promise can only be resolved or rejected once. The first invocation of the callback settles the Promise. Subsequent calls are silently ignored. If your function relies on multi-fire callbacks (e.g., EventEmitter pattern), promisification is not the correct abstraction - use an Observable or async iterator instead.
If the original function references this internally (e.g., this.doSomething()), extracting it from its object and wrapping it loses the implicit binding. You must pass the parent object as the second argument to promisify. Without it, this resolves to undefined in strict mode or the global object in sloppy mode, causing a runtime TypeError.
util.promisify (Node ≥ 8) supports a custom Symbol (util.promisify.custom) allowing functions to provide their own Promise implementation. This converter generates equivalent wrapper code without requiring a Node.js runtime. It also handles multi-result callbacks by resolving with an array, while util.promisify only returns the first result unless custom is defined.
Yes. Toggle the "Error-first callback" option off. In that mode, the generated wrapper treats the first callback argument as a successful result rather than an error object. All callback arguments are passed directly to resolve. The Promise never rejects unless the function itself throws synchronously.
The converter outputs plain JavaScript. For TypeScript, you would need to add generic type annotations manually. The generated wrapper signature mirrors the original minus the callback parameter, returning Promise<T> where T is the callback's result type. TypeScript ≥ 4.7 can infer this with util.promisify natively.
No. The generated wrapper uses rest parameters (...args), which sets .length to 0. The original function's .length reflects its declared parameter count including the callback. If downstream code inspects .length for arity checking, you must handle this manually via Object.defineProperty.