From the JavaScript course I am doing now:
A Promise is like placing an order at a restaurant. You receive a ticket (Promise object) that indicates your order is being processed. The order can either be successfully delivered (resolved) or canceled (rejected), and you can attach actions (.then() and .catch()) to handle either outcome.
I changed the analogy a little, added some more details and asked AI to finish it. Here’s the end result:
1. Place an order at McDonald’s and receive a buzzer.
- This is creating a new Promise – it represents a future value.
- The buzzer (Promise) is now in a pending state.
2. Waiting for food preparation happens in the background.
- This is an asynchronous operation like
setTimeout()
or an API call. - The kitchen staff (JavaScript engine) is working on your order without blocking other customers.
3. When food is ready, the employee pushes a button to make your buzzer go off.
- This is the Promise’s state changing to fulfilled.
- The
resolve()
function is called by the code handling the async operation.
4. The prepared food is handed to you when you return to the counter.
- This is the data that the Promise resolved with.
- The value passed to
resolve()
becomes available in the .then()
handler.
5. If they’re out of fries or there’s a problem with your order, the manager comes to your table to explain the issue.
- This is the Promise’s state changing to rejected.
- The
reject()
function is called with an error reason.
6. The explanation of what went wrong (e.g., “We’re out of fries”) is the error information.
- This is the error data that the Promise rejected with.
- The value passed to
reject()
becomes available in the .catch()
handler.
7. You deciding what to do next after getting your food or hearing about the problem.
- This is your code in the
.then()
or.catch()
handlers executing. - You might be satisfied with your food or order something else instead.
8. Once you’ve either received your food or dealt with the problem, your interaction with that specific order is complete.
- The Promise is now in a settled state (either fulfilled or rejected).
- A Promise can never change state again after being settled.
This analogy covers all three possible states of a Promise:
- Pending: Order placed, waiting for food
- Fulfilled: Food ready and delivered
- Rejected: Order cannot be completed due to a problem
In code form
const orderFood = menuItem => {
return new Promise((resolve, reject) => {
console.log(`Order for ${menuItem} received. Please wait...`);
// Simulate food preparation (async operation)
setTimeout(() => {
// Randomly succeed or fail the order
if (Math.random() > 0.2) {
// Food prepared successfully
const food = `🍔 Fresh ${menuItem}`;
resolve(food); // Promise fulfilled
} else {
// Something went wrong
reject(`Sorry, we're out of ${menuItem}`); // Promise rejected
}
}, 2000);
});
};
// Using the Promise
orderFood('fries')
.then(food => {
console.log(`Enjoy your ${food}!`);
})
.catch(problem => {
console.log(`Order failed: ${problem}`);
})
.finally(() => {
console.log("Thank you for visiting McDonald's");
});
Execution Flow Breakdown
1. When orderFood('fries')
is called:
- The function is executed immediately
- A new Promise object is created
- The executor function (the function passed to the Promise constructor) runs synchronously
2. Inside the executor function:
console.log(Order for ${menuItem} received. Please wait...)
executes immediatelysetTimeout()
is called, which schedules the callback to run later- The Promise object is returned to the caller (still in pending state)
3. After the Promise is returned:
- The
.then()
and.catch()
handlers are attached to the Promise - These handlers are not executed yet – they’re just registered to run later
4. When the timeout completes (after 2000ms):
- The timeout callback runs
- Either
resolve()
or reject()
is called - This changes the Promise state to fulfilled or rejected
- The appropriate handler (
.then()
or.catch()
) is queued to run in the next event loop iteration
When the promise is fulfilled:
When the promise is rejected:
Addendum
The most confusing part to me was what resolve
and reject
functions are. Where are they defined? What is their definition?
My notes:
resolve
and reject
are the names we usually give to these parameters. They can be anything else just like any other function’s arguments.
The resolve
and reject
functions are provided by the JavaScript engine when you create a new Promise – more specifically, the constructor()
function of the Promise class. They are automatically passed to the executor function (the function you provide to the Promise constructor).
The Promise constructor signature looks like this:
new Promise(executor);
where executor
is a function with this signature:
function executor(resolveFunction, rejectFunction) {
// Your code here
}
The resolve
and reject functions are internal functions provided by the JavaScript engine.
While you can’t see its actual implementation, conceptually the resolve
function:
- Changes the state of the Promise from “pending” to “fulfilled”
- Sets the Promise’s result value to whatever you pass to it
- Schedules any attached
.then()
callbacks to run in the next event loop iteration
Another example
The Promise constructor provides two parameters to the executor function. It is up to you whether you use just one (as resolve
) or both (resolve
and reject
).
const wait = milliseconds => {
return new Promise((resolve, reject) => {
// Validate input
if (typeof milliseconds !== 'number' || milliseconds < 0) {
reject(new Error('milliseconds must be a positive number'));
return;
}
// Set up the timer
setTimeout(() => {
resolve('Timer completed!'); // Can pass a value
}, milliseconds);
});
}
// Usage
wait(1000)
.then(message => console.log(message)) // "Timer completed!"
.catch(error => console.error(error));
You can pass a value to resolve()
which becomes available in the .then()
callback.
When you call new Promise()
, the JavaScript engine:
- Creates a new Promise object in “pending” state
- Creates two special functions (commonly called
resolve
and reject
) - Calls your executor function with these two functions as arguments
- When you call
resolve()
, it triggers the Promise’s internal state change