new Promise()
Creates a promise whose settlement you control with resolve and reject functions.
new Promise(executor)- Added in JavaScript ES2015
Parameters
| Parameter | Type | Description |
|---|---|---|
$executor | Function | A function run synchronously by the constructor. It receives two functions, conventionally named resolveFunc and rejectFunc. Any error thrown inside it rejects the promise, and its return value is ignored. |
$resolveFunc | Function | Passed into the executor. Called with a single value to resolve the promise. If that value is a thenable, the promise locks in to match it instead of fulfilling with it. |
$rejectFunc | Function | Passed into the executor. Called with a single rejection reason, conventionally an Error instance. Semantics are similar to a throw statement. |
Return value
PromiseA Promise object that becomes resolved when either resolveFunc or rejectFunc is invoked. If neither is called, the promise stays pending forever.
Errors
TypeError if Promise() is called without the new operator.
The constructor is the low-level way to build a promise: you hand it an executor function, and that function decides when the promise settles by calling the two functions it is given. The executor runs synchronously, immediately, before the constructor returns — only the settlement is asynchronous.
When to reach for it
Almost exclusively to adapt something that is not promise-based yet: a callback API, an event listener, a timer. If you already have a promise, or a value, use Promise.resolve() or an async function instead. Wrapping an existing promise in new Promise is the classic explicit construction antipattern — it adds a layer that swallows rejections you forgot to forward.
What trips people up
- The promise settles once. The first
resolveorrejectwins; later calls are silently ignored, and no error is raised to tell you. - Calling
resolvedoes not stop the executor. Code after it keeps running — usereturn resolve(v)if you mean to bail out. - Errors thrown synchronously in the executor become a rejection, but errors thrown later inside an asynchronous callback do not. Those escape as uncaught exceptions, and the promise hangs pending forever.
Example
When to use it
- Turn a Node-style error-first callback API into something you can await
- Build a delay/sleep helper on top of setTimeout
- Resolve when an event fires once, such as a load or ready signal
- Expose a manually controlled promise for a queue or a gate
Frequently asked questions
Why is my promise stuck pending forever?
Because neither resolve nor reject was ever called — most often an early return, a branch you forgot, or an error thrown inside an asynchronous callback in the executor. A promise with no settlement path simply never settles, and awaiting it hangs.
Should I wrap an existing promise in new Promise?
No — that is the explicit construction antipattern. Use the promise directly, or chain then()/await on it; wrapping adds a layer where rejections get lost if you do not forward them by hand.
Does calling resolve() stop the rest of the executor?
No, resolve() is an ordinary function call and execution continues on the next line. Write return resolve(value) if you want to exit the executor at that point.
More examples
Promisify a callback API
The error-first callback is bridged into promise land: a non-null err becomes a rejection, a value becomes the fulfillment. The output shows "dark" for the known key and the error message for the unknown one.
function readSetting(key, callback) {
setTimeout(() => {
if (key === "theme") callback(null, "dark");
else callback(new Error(`unknown key: ${key}`));
}, 10);
}
const readSettingAsync = (key) =>
new Promise((resolve, reject) => {
readSetting(key, (err, value) => (err ? reject(err) : resolve(value)));
});
console.log(await readSettingAsync("theme"));
console.log(await readSettingAsync("locale").catch((e) => e.message));Throwing in the executor, and settling only once
A synchronous throw in the executor is converted into a rejection, so catch() sees it. The second promise prints "first": once settled, the later resolve and reject calls are discarded without any warning.
const p = new Promise(() => {
throw new Error("executor blew up");
});
p.catch((e) => console.log("caught:", e.message));
const q = new Promise((resolve, reject) => {
resolve("first");
resolve("second");
reject(new Error("ignored"));
});
console.log(await q);
Discussion