0
0
JavascriptHow-ToBeginner · 2 min read

JavaScript How to Convert Callback to Async Await

To convert a callback to async/await in JavaScript, wrap the callback-based function in a Promise and then use await to wait for it inside an async function, like const result = await new Promise((resolve, reject) => callbackFunction(args, (err, data) => err ? reject(err) : resolve(data))).
📋

Examples

InputcallbackFunction(5, (err, data) => { if(err) console.error(err); else console.log(data); })
Output25
Inputasync function example() { const result = await promiseFunction(3); console.log(result); } example();
Output9
InputcallbackFunction(null, (err, data) => { if(err) console.error(err); else console.log(data); })
OutputError handled
🧠

How to Think About It

First, identify the callback function that takes an error and data as arguments. Then, create a new Promise that calls this function and resolves or rejects based on the callback's result. Finally, use async/await syntax to call this Promise and handle the result or error cleanly.
📐

Algorithm

1
Identify the callback-based function you want to convert.
2
Create a new Promise that calls this function and handles resolve/reject inside the callback.
3
Define an async function to use await on the Promise.
4
Call the async function and handle the result or error with try/catch.
💻

Code

javascript
function multiplyAsync(x, callback) {
  setTimeout(() => {
    if (typeof x !== 'number') return callback('Input must be a number');
    callback(null, x * x);
  }, 100);
}

function multiplyPromise(x) {
  return new Promise((resolve, reject) => {
    multiplyAsync(x, (err, result) => {
      if (err) reject(err);
      else resolve(result);
    });
  });
}

async function run() {
  try {
    const result = await multiplyPromise(5);
    console.log(result);
  } catch (error) {
    console.error('Error:', error);
  }
}

run();
Output
25
🔍

Dry Run

Let's trace multiplyAsync(5) converted to async/await through the code

1

Call multiplyPromise(5)

Returns a Promise that calls multiplyAsync(5, callback)

2

Inside multiplyAsync, after 100ms delay

Checks if 5 is a number, then calls callback(null, 25)

3

Promise resolves with 25

await receives 25 and assigns to result

StepActionValue
1Call multiplyPromise(5)Promise pending
2multiplyAsync calls callbackcallback(null, 25)
3Promise resolves25 assigned to result
💡

Why This Works

Step 1: Wrap callback in Promise

The callback function is wrapped inside a Promise constructor to convert it into a Promise-based function.

Step 2: Use async function with await

An async function uses await to pause execution until the Promise resolves or rejects.

Step 3: Handle errors with try/catch

Errors from the callback are caught by rejecting the Promise and handled in the async function using try/catch.

🔄

Alternative Approaches

Using util.promisify
javascript
const util = require('util');
const multiplyPromise = util.promisify(multiplyAsync);

async function run() {
  try {
    const result = await multiplyPromise(5);
    console.log(result);
  } catch (error) {
    console.error('Error:', error);
  }
}

run();
This method is simpler but requires Node.js environment and the callback must follow Node.js style (error-first).
Manual Promise wrapper with inline async
javascript
async function multiplyAsyncAwait(x) {
  return new Promise((resolve, reject) => {
    multiplyAsync(x, (err, result) => {
      if (err) reject(err);
      else resolve(result);
    });
  });
}

(async () => {
  try {
    const result = await multiplyAsyncAwait(5);
    console.log(result);
  } catch (e) {
    console.error(e);
  }
})();
This approach is flexible and works in any environment but requires manual Promise wrapping.

Complexity: O(1) time, O(1) space

Time Complexity

The conversion does not add loops or recursion; it only wraps existing asynchronous calls, so time complexity remains constant.

Space Complexity

Extra space is used for the Promise object, but this is minimal and constant.

Which Approach is Fastest?

Using util.promisify is fastest and cleanest in Node.js, while manual Promise wrapping is more flexible but slightly more verbose.

ApproachTimeSpaceBest For
Manual Promise WrapperO(1)O(1)Any environment, flexible
util.promisifyO(1)O(1)Node.js, standard callbacks
Inline async wrapperO(1)O(1)Quick conversion, small code
💡
Wrap callback functions in a Promise and use async/await inside an async function for cleaner code.
⚠️
Forgetting to return or await the Promise causes the async/await conversion to fail silently.