Encodera

Thanks for reading!

Donate to the site — we work hard for you.

How to turn a callback function into a promise

Short answer

Create a new Promise and call resolve on success and reject on error inside the callback:

function loadData(id, callback) {
  setTimeout(() => {
    if (id < 0) callback(new Error('Invalid id'));
    else callback(null, { id, title: 'Report' });
  }, 50);
}
 
const loadDataAsync = (id) =>
  new Promise((resolve, reject) => {
    loadData(id, (error, data) => (error ? reject(error) : resolve(data)));
  });
 
const data = await loadDataAsync(7);
console.log(data.title);
 
try {
  await loadDataAsync(-1);
} catch (error) {
  console.log(error.message);
}

Output:

Report
Invalid id

An image in the browser

Events like load and error turn into a promise the same way:

const loadImage = (src) =>
  new Promise((resolve, reject) => {
    const image = new Image();
    image.onload = () => resolve(image);
    image.onerror = () => reject(new Error(`Could not load ${src}`));
    image.src = src;
  });
 
const logo = await loadImage('/logo.png');
document.body.append(logo);

In Node.js

Node.js has a ready helper promisify() for functions with a callback in the style of (error, result):

import { promisify } from 'node:util';
 
function add(a, b, callback) {
  setTimeout(() => callback(null, a + b), 10);
}
 
const addAsync = promisify(add);
 
console.log(await addAsync(2, 3));

Output:

5

Common mistake

An error thrown inside a timer callback does not reach reject() by itself. Catch it and call reject() yourself, otherwise the promise waits forever.

const parseLater = (text) =>
  new Promise((resolve, reject) => {
    setTimeout(() => {
      try {
        resolve(JSON.parse(text));
      } catch (error) {
        reject(error);
      }
    }, 10);
  });
 
console.log(await parseLater('{bad').catch((error) => error.name));

Output:

SyntaxError

Functions used in this recipe

  • Promise — A promise of a result that will be ready later: success or failure.
  • async function — A function that always returns a promise and lets you use await inside.

Thanks for reading!

Donate to the site — we work hard for you.