new Promise()

Creates a promise whose settlement you control with resolve and reject functions.

Signature
new Promise(executor)
  • Added in JavaScript ES2015

Parameters

ParameterTypeDescription
$executorFunctionA 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.
$resolveFuncFunctionPassed 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.
$rejectFuncFunctionPassed 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 resolve or reject wins; later calls are silently ignored, and no error is raised to tell you.
  • Calling resolve does not stop the executor. Code after it keeps running — use return 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

Try it yourself
Loading editor…
Press Run to execute the code.

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.

Example · javascript
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.

Example · javascript
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

  • Be the first to comment on this lesson.