JavaScript Promises Explained: new Promise, then, catch and Examples (2026)

Header image: JavaScript Promises, a timeline showing a new promise starting as pending, then becoming fulfilled through resolve or rejected through reject, and its then or catch handler running.

Hey friends,

A JavaScript promise is an object that stands for a value you don't have yet: it starts pending, then settles once as either fulfilled with a value or rejected with an error, and your then and catch handlers run when it does. That definition comes straight from MDN's Promise reference, and it's the idea the Salesforce JavaScript Developer exam builds on in its Asynchronous Programming section (13% of the exam).

Below: the three states, how to create a promise, chaining, returning promises from functions, error handling, and the mistakes I see most. Every snippet runs in a browser console or Node.js.

What are the three states of a JavaScript promise?

StateMeaningWhat runs
pendingInitial state. Not fulfilled or rejected yet.Nothing yet
fulfilledThe operation completed. The promise has a value.then handlers
rejectedThe operation failed. The promise has a reason (usually an Error).catch handlers, or the second argument of then

A promise that's fulfilled or rejected is called settled. It settles once. Calling resolve or reject again after that does nothing, which is a favorite exam trick.

How do you create a new Promise in JavaScript?

Pass an executor function to new Promise. The executor runs right away, synchronously, and gets two functions: resolve and reject. Call one of them when your work finishes.

wait.js
1function wait(ms) {
2  return new Promise((resolve, reject) => {
3    if (ms < 0) {
4      reject(new Error('ms must be 0 or more'));
5      return;
6    }
7    setTimeout(() => resolve(`waited ${ms} ms`), ms);
8  });
9}
10
11wait(500).then((msg) => console.log(msg)); // waited 500 ms

Two details worth remembering. First, code in the executor runs immediately, before new Promise even returns. Second, if the executor throws, the promise is rejected with that error, so you don't need a try/catch inside it for that case.

You rarely need new Promise for APIs that already return promises, like fetch. Wrapping one promise in another is a known anti-pattern. Use it to wrap callback-style APIs such as setTimeout.

How do then, catch and finally work?

then takes up to two callbacks, one for fulfilled and one for rejected, and always returns a new promise. That's what makes chaining work. Per the MDN then() page, the new promise follows whatever your callback returns:

  • Return a plain value, and the next promise fulfills with it.
  • Return a promise, and the next one waits for it and copies its result.
  • Throw an error, and the next promise rejects with it.
  • Return nothing, and the next promise fulfills with undefined.
chain.js
1fetch('/api/accounts')
2  .then((res) => {
3    if (!res.ok) throw new Error(`HTTP ${res.status}`);
4    return res.json();          // a promise: the chain waits for it
5  })
6  .then((accounts) => accounts.filter((a) => a.active))
7  .then((active) => console.log(active.length, 'active'))
8  .catch((err) => console.error('Failed:', err.message))
9  .finally(() => console.log('done either way'));

catch(fn) is shorthand for then(undefined, fn). One catch at the end handles a rejection from any step above it. finally runs on both outcomes and passes the original result through, so it's the place for cleanup like hiding a spinner.

Cert Lab by Nick Frates

Let the JavaScript Developer Cert Lab test you to success

Scenario questions on promises, async/await, the event loop and the rest of the seven exam sections, with an explanation for every option.

Start the JavaScript Developer Cert Lab for $9.99 →

Not ready to buy? Try a free lesson and see how fast you learn.

How do you return a promise from a function?

Return it. If a function starts async work, return the promise so callers can wait for it. Forgetting the return inside a then callback is the single most common promise bug: the chain moves on before the inner work finishes.

returnPromise.js
1// Broken: the inner promise is not returned
2getUser().then((user) => { getOrders(user.id); })
3         .then((orders) => console.log(orders)); // undefined
4
5// Fixed: return it, and the chain waits
6getUser().then((user) => getOrders(user.id))
7         .then((orders) => console.log(orders)); // the orders

To get the result of a promise, you can't read it synchronously. Use then, or await inside an async function. My async/await guide covers that side.

Callbacks vs promises: what's the difference?

A callback is a function you pass in to be called later. Nest a few and you get callback hell, with error handling repeated at every level. Promises flatten that into a chain with one error path. The MDN Using promises guide walks through the same refactor.

callbackToPromise.js
1// Callback style
2readConfig((err, cfg) => {
3  if (err) return handle(err);
4  connect(cfg, (err, conn) => {
5    if (err) return handle(err);
6    query(conn, (err, rows) => { /* ... */ });
7  });
8});
9
10// Promise style
11readConfig().then(connect).then(query).catch(handle);

When do promise callbacks run?

Never immediately. Even if a promise is already fulfilled, its then callback goes onto the microtask queue and runs after the current synchronous code finishes. This prints 1, 3, 2:

order.js
1console.log(1);
2Promise.resolve().then(() => console.log(2));
3console.log(3);

Questions like this show up on the exam all the time. My JavaScript event loop guide explains microtasks vs tasks (setTimeout).

What promise mistakes should you avoid?

  • Forgetting to return inside then. The next step gets undefined and runs too early.
  • No catch at the end. Browsers log an unhandled rejection to the console. Since Node.js 15, the default is to raise it as an uncaught exception, which stops the process (Node.js CLI docs).
  • Wrapping a promise in new Promise. Just return the existing promise.
  • Running independent calls one after another. Start them together with Promise.all.
  • Expecting resolve to stop the executor. Code after resolve() still runs. Add return if you need to stop.

For running several promises at once, see Promise.all, allSettled, any and race.

Quick backstory. I loved Focus on Force and used it on my way to 17 Salesforce certifications. At first I read the study guide cover to cover, then took the tests. What I eventually noticed: I learned way faster when I skipped ahead and took practice tests rapid-fire, reading the explanation for every miss. So I built Cert Lab around fast testing, with up-to-date doc links in every explanation. It's designed to test you to success.

FAQ

What is a promise in JavaScript, in simple terms?

An object that represents the eventual result of an async operation. It starts pending and settles once, as fulfilled with a value or rejected with an error.

Is a promise synchronous or asynchronous?

The executor passed to new Promise runs synchronously. The then, catch and finally callbacks always run asynchronously, as microtasks.

What does then return?

A new promise. That's why you can chain then calls.

Are promises on the Salesforce JavaScript Developer exam?

Yes. Asynchronous Programming is 13% of the exam, and promises, async/await and the event loop are its core. My JavaScript Developer study guide maps every section.

Where should you go next?

Nick Frates, a senior Salesforce developer with 17 certifications, built the JavaScript Developer Cert Lab at nickfrates.com: rapid-fire practice questions for every exam section, each answer explained.

Cert Lab by Nick Frates

Let the JavaScript Developer Cert Lab test you to success

Lessons, flashcards, a quiz for each of the seven exam sections and full practice exams, every answer explained.

Start the JavaScript Developer Cert Lab for $9.99 →

Not ready to buy? Try a free lesson and see how fast you learn.

Hope this helps!

Best,

Nick

Keep reading

See all posts →

Salesforce Saturdays

Join 1,033 Salesforce pros getting one 10-minute tip on Salesforce tech or career growth every Saturday.