How do you wrap a callback-based API into a Promise?

This tests Promise constructor mechanics and callback migration. A strong answer returns a new Promise, calls the legacy function, maps success to resolve and errors to reject.
What's really being asked
Your understanding of the Promise constructor as an interoperability layer between legacy Node-style or browser callback APIs and modern async code. The interviewer wants to see that you know promises are created with new Promise, that you manually control resolution and rejection, and that you understand the difference between a function that takes a callback and a function that returns a Promise.
The full answer
First, return a new Promise from the wrapper function so callers can use then and catch. Second, inside the executor function, invoke the original legacy function with the provided id. Third, pass a callback that checks for an error argument; if present, call reject with that error, otherwise call resolve with the result. Fourth, ensure you do not return the result of the legacy call, because callback-based functions often return undefined, and the wrapper must return the Promise itself.
The mistakes people make
A major red flag is forgetting to handle the error branch and only calling resolve, which causes errors to silently disappear. Another is calling resolve with the error instead of reject, which makes failures look like successes. Some candidates try to use async and await inside the wrapper without returning a new Promise, or they return the legacy function's undefined return value instead of the Promise object. A subtle mistake is assuming the callback signature is always node-style error-first; in the browser it might be success-first, so a senior candidate should ask or check the callback convention.
What usually comes next
The interviewer might ask how to promisify an entire module or API surface, which leads to util.promisify in Node or a manual wrapper factory. They might ask what happens if the legacy function throws synchronously, which should be caught and passed to reject. They could also ask about TypeScript typing, specifically how to type the wrapper so it infers the resolve type from the callback and uses unknown or Error for the reject type.
A concrete example
Imagine a legacy function getUser(id, callback) where callback is function(err, user). The wrapper is function getUserAsync(id) { return new Promise((resolve, reject) => { getUser(id, (err, user) => { if (err) { reject(err); return; } resolve(user); }); }); }. This returns a Promise, maps the error-first callback correctly, and does not leak the undefined return of getUser.
Interview question
When wrapping getUser(id, cb) into a Promise, which approach is correct?
- a.Return new Promise and pass a callback that rejects on err and resolves with userCorrect
- b.Pass a callback that resolves with the first argument and rejects with the second
- c.Make the wrapper async and await getUser(id) without creating a Promise
- d.Return getUser(id) directly since the Promise resolves automatically
Why? this is the answer
The wrapper must return a new Promise and map the error-first callback to reject on error and resolve on success. Option D is wrong because legacy callback functions typically return undefined rather than a Promise.
Just read this? Test yourself on what you have been reading.
Read the original → developer.mozilla.org
- #promises
- #callbacks
- #async
- #javascript
- #typescript
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 promises — each one lists the topics its interview covers.
See open roles