The Promise Constructor: Wrapping Old Callbacks

The Promise constructor turns old callback-style functions into modern promises you can await. Use it to "promisify" APIs like setTimeout that don't return promises. The footgun is wrapping already-promise-based code, creating unnecessary complexity.
Why it exists
JavaScript's early asynchronous operations used callbacks, leading to nested, hard-to-read code often called "callback hell." Promises were introduced to standardize async handling. The Promise constructor exists specifically to bridge this gap, allowing developers to wrap old, callback-based APIs and make them compatible with modern async/await syntax.
The mental model
Think of the Promise constructor as a translation layer. You give it a function (the "executor") that knows how to speak the old "callback" language. Inside, you perform your async task and then tell the constructor when it's done by calling one of two functions it provides: resolve for success or reject for failure. The constructor then returns a standard promise object that speaks the modern async/await language.
How it works
You create a promise with new Promise((resolve, reject) => { ... }). The function you pass, called the executor, runs immediately. The executor is given two arguments: the resolve function and the reject function. Inside the executor, you start your asynchronous operation. When the operation completes successfully, you call resolve(value). If it fails, you call reject(error). Any uncaught error thrown inside the executor will also automatically call reject.
When to use it
Use the Promise constructor when you need to interface with an API that is asynchronous but does not return a promise. This is common with older Node.js modules (e.g., fs.readFile without using fs/promises), browser APIs like setTimeout, or libraries that use an event-emitter or callback pattern for completion. It's the primary tool for "promisifying" legacy code.
When not to use it
Never wrap a function that already returns a promise. For example, new Promise(resolve => resolve(fetch('...'))) is redundant and an anti-pattern. The fetch function already returns a promise. Wrapping it creates an unnecessary, deeper promise chain that can obscure errors and make debugging harder. If your task is already promise-based, just use it directly.
One canonical example
A classic use case is creating a delay function with setTimeout, which is callback-based.
function delay(ms) { return new Promise(resolve => setTimeout(resolve, ms)); }
async function main() { console.log('Waiting...'); await delay(1000); console.log('Done.'); }Here, new Promise wraps setTimeout. The resolve function is passed directly as the callback to setTimeout. After 1000ms, setTimeout calls resolve(), which fulfills the promise, allowing the await to complete.
Interview question
According to the card, what is the primary and most appropriate use case for the Promise constructor (new Promise(...))?
- a.To wrap a function that already returns a promise, adding an extra layer of control.
- b.To create a new promise that immediately resolves or rejects with a static value.
- c.To define a new, complex asynchronous operation from scratch without relying on any external APIs.
- d.To transform an existing asynchronous function that uses callbacks into a promise-based one.Correct
Why? this is the answer
The card states the Promise constructor's purpose is to "bridge this gap, allowing developers to wrap old, callback-based APIs" and is the "primary tool for 'promisifying' legacy code." Option A describes an anti-pattern explicitly warned against in the card.
Just read this? Test yourself on what you have been reading.
Read the original → developer.mozilla.org
- #javascript
- #async
- #promise
- #web-api
You just looked this up. Could you explain it out loud?
That is the part interviews actually test. Tezvyn takes questions like this one and gives you what the interviewer is really checking, the answer that lands, and the mistake that ends the conversation, in the four minutes before your next meeting.
The iPhone app is on the way
We are building it. Until it lands, nothing here is held back from you: every interview card, your saved cards, streaks and the job board all work in Safari, plus hundreds of free practice quizzes of thirty questions each. Sign in and it all carries over to the app the day it arrives.
Want it as an icon? Tap Share at the bottom of Safari, then Add to Home Screen. It opens full screen and the cards you have read stay available offline.
We are hiring for this. Open roles that interview on javascript — each one lists the topics its interview covers.
See open roles