Convert Callback Based Function to Promise Based Function - Problem

In the evolution of JavaScript asynchronous programming, we've moved from callback-based functions to Promise-based functions for better error handling and code readability. Your task is to create a promisify function that bridges this gap.

The Challenge: Write a function that accepts a callback-based function fn and converts it into a promise-based function. The original function fn follows the Node.js callback convention where:

  • The first parameter is always a callback function
  • The callback receives (result, error) as parameters
  • If there's an error, it's passed as the second argument
  • If successful, the result is passed as the first argument

Your promisify function should:

  • Return a new function that returns a Promise
  • Resolve with the result when the callback is called without an error
  • Reject with the error when the callback is called with an error

Example transformation:

// Original callback-based function
function sum(callback, a, b) {
  if (a < 0 || b < 0) {
    callback(undefined, Error('a and b must be positive'));
  } else {
    callback(a + b);
  }
}

// After promisify
const promisedSum = promisify(sum);
promisedSum(3, 4).then(result => console.log(result)); // 7
promisedSum(-1, 4).catch(err => console.log(err.message)); // 'a and b must be positive'

Input & Output

example_1.js โ€” Basic Sum Function
$ Input: fn = function sum(callback, a, b) { if (a < 0 || b < 0) { callback(undefined, new Error('a and b must be positive')); } else { callback(a + b); } } args = [3, 4]
โ€บ Output: Promise resolves to 7
๐Ÿ’ก Note: The sum function with positive numbers resolves successfully with the result 7
example_2.js โ€” Error Case
$ Input: fn = function sum(callback, a, b) { if (a < 0 || b < 0) { callback(undefined, new Error('a and b must be positive')); } else { callback(a + b); } } args = [-1, 4]
โ€บ Output: Promise rejects with Error('a and b must be positive')
๐Ÿ’ก Note: When a negative number is provided, the function calls the callback with an error, causing the Promise to reject
example_3.js โ€” Async File Operation
$ Input: fn = function readFile(callback, filename) { setTimeout(() => { if (filename === 'test.txt') { callback('file contents'); } else { callback(undefined, new Error('File not found')); } }, 100); } args = ['test.txt']
โ€บ Output: Promise resolves to 'file contents'
๐Ÿ’ก Note: The promisified function handles asynchronous operations correctly, resolving with the file contents after the timeout

Constraints

  • The original function fn always takes callback as the first parameter
  • Callback follows Node.js convention: callback(result, error)
  • If error exists, result should be undefined
  • Your promisify function should handle any number of additional arguments
  • The returned function must return a proper Promise object

Visualization

Tap to expand
Callback-basedFunctionPromisifyWrapperPromise-basedFunctionPromise Constructor Magic1. Create custom callback2. Call original function3. Handle callback result4. Resolve/Reject Promise
Understanding the Visualization
1
Receive Original Function
Accept the callback-based function that needs to be converted
2
Create Wrapper Function
Return a new function that accepts the same arguments as the original
3
Promise Constructor
Inside wrapper, create Promise with resolve/reject handlers
4
Custom Callback
Create callback that resolves/rejects Promise based on error parameter
5
Call Original Function
Execute original function with our custom callback and user arguments
Key Takeaway
๐ŸŽฏ Key Insight: The promisify pattern uses closure to capture the original function and creates a bridge between callback and Promise paradigms, making legacy code compatible with modern async/await syntax.
Asked in
Node.js 45 Google 35 Microsoft 28 Amazon 22
28.4K Views
Medium Frequency
~15 min Avg. Time
856 Likes
Ln 1, Col 1
Smart Actions
๐Ÿ’ก Explanation
AI Ready
๐Ÿ’ก Suggestion Tab to accept Esc to dismiss
// Output will appear here after running code
Code Editor Closed
Click the red button to reopen